Anim: rename slot name to slot identifier
This PR renames `ActionSlot::name` to `ActionSlot::identifier` for both DNA and RNA, and also renames related methods, functions, constants, and comments. The purpose of this rename is to help make it clear that this is not a "name" in the traditional sense, but rather is a composite of the slot name + id type for lookup purposes. Ref: #130892 Pull Request: https://projects.blender.org/blender/blender/pulls/130740
This commit is contained in:
committed by
Nathan Vegdahl
parent
8121d47960
commit
c0fd193abf
@@ -145,42 +145,42 @@ class Action : public ::bAction {
|
||||
const Slot *slot_for_handle(slot_handle_t handle) const;
|
||||
|
||||
/**
|
||||
* Set the slot name, ensure it is unique, and propagate the new name to
|
||||
* Set the slot identifier, ensure it is unique, and propagate the new identifier to
|
||||
* all data-blocks that use it.
|
||||
*
|
||||
* This has to be done on the Action level to ensure each slot has a
|
||||
* unique name within the Action.
|
||||
* unique identifier within the Action.
|
||||
*
|
||||
* \note This does NOT ensure the first two characters match the ID type of
|
||||
* this slot. This is the caller's responsibility.
|
||||
*
|
||||
* \see #Action::slot_name_define
|
||||
* \see #Action::slot_name_propagate
|
||||
* \see #Action::slot_identifier_define
|
||||
* \see #Action::slot_identifier_propagate
|
||||
*/
|
||||
void slot_name_set(Main &bmain, Slot &slot, StringRefNull new_name);
|
||||
void slot_identifier_set(Main &bmain, Slot &slot, StringRefNull new_identifier);
|
||||
|
||||
/**
|
||||
* Set the slot name, and ensure it is unique.
|
||||
* Set the slot identifier, and ensure it is unique.
|
||||
*
|
||||
* \note This does NOT ensure the first two characters match the ID type of
|
||||
* this slot. This is the caller's responsibility.
|
||||
*
|
||||
* \see #Action::slot_name_set
|
||||
* \see #Action::slot_name_propagate
|
||||
* \see #Action::slot_identifier_set
|
||||
* \see #Action::slot_identifier_propagate
|
||||
*/
|
||||
void slot_name_define(Slot &slot, StringRefNull new_name);
|
||||
void slot_identifier_define(Slot &slot, StringRefNull new_identifier);
|
||||
|
||||
/**
|
||||
* Update the `AnimData::action_slot_name` field of any ID that is animated by
|
||||
* this Slot.
|
||||
*
|
||||
* Should be called after `slot_name_define(slot)`. This is implemented as a separate
|
||||
* Should be called after `slot_identifier_define(slot)`. This is implemented as a separate
|
||||
* function due to the need to access `bmain`, which is available in the RNA on-property-update
|
||||
* handler, but not in the RNA property setter.
|
||||
*/
|
||||
void slot_name_propagate(Main &bmain, const Slot &slot);
|
||||
void slot_identifier_propagate(Main &bmain, const Slot &slot);
|
||||
|
||||
Slot *slot_find_by_name(StringRefNull slot_name);
|
||||
Slot *slot_find_by_identifier(StringRefNull slot_identifier);
|
||||
|
||||
/**
|
||||
* Create a new, unused Slot.
|
||||
@@ -249,7 +249,7 @@ class Action : public ::bAction {
|
||||
* - `animated_id.name`.
|
||||
*
|
||||
* Note that this is different from #slot_for_id, which does not use the
|
||||
* slot name, and only works when this Action is already assigned. */
|
||||
* slot identifier, and only works when this Action is already assigned. */
|
||||
Slot *find_suitable_slot_for(const ID &animated_id);
|
||||
|
||||
/**
|
||||
@@ -323,8 +323,8 @@ class Action : public ::bAction {
|
||||
float2 get_frame_range_of_keys(bool include_modifiers) const ATTR_WARN_UNUSED_RESULT;
|
||||
|
||||
/**
|
||||
* Set the slot's ID type to that of the animated ID, ensure the name
|
||||
* prefix is set accordingly, and that the name is unique within the
|
||||
* Set the slot's ID type to that of the animated ID, ensure the identifier
|
||||
* prefix is set accordingly, and that the identifier is unique within the
|
||||
* Action.
|
||||
*
|
||||
* This is a low-level function, and shouldn't be called directly outside of
|
||||
@@ -378,14 +378,14 @@ class Action : public ::bAction {
|
||||
Slot &slot_allocate();
|
||||
|
||||
/**
|
||||
* Ensure the slot name prefix matches its ID type.
|
||||
* Ensure the slot identifier prefix matches its ID type.
|
||||
*
|
||||
* This ensures that the first two characters match the ID type of
|
||||
* this slot.
|
||||
*
|
||||
* \see #Action::slot_name_propagate
|
||||
* \see #Action::slot_identifier_propagate
|
||||
*/
|
||||
void slot_name_ensure_prefix(Slot &slot);
|
||||
void slot_identifier_ensure_prefix(Slot &slot);
|
||||
};
|
||||
static_assert(sizeof(Action) == sizeof(::bAction),
|
||||
"DNA struct and its C++ wrapper must have the same size");
|
||||
@@ -620,28 +620,28 @@ class Slot : public ::ActionSlot {
|
||||
constexpr static slot_handle_t unassigned = 0;
|
||||
|
||||
/**
|
||||
* Slot names consist of a two-character ID code, then the display name.
|
||||
* This means that the minimum length of a valid name is 3 characters.
|
||||
* Slot identifiers consist of a two-character ID code, then the display name.
|
||||
* This means that the minimum length of a valid identifier is 3 characters.
|
||||
*/
|
||||
constexpr static int name_length_min = 3;
|
||||
constexpr static int identifier_length_min = 3;
|
||||
|
||||
constexpr static int name_length_max = MAX_ID_NAME;
|
||||
static_assert(sizeof(AnimData::slot_name) == name_length_max);
|
||||
static_assert(sizeof(NlaStrip::action_slot_name) == name_length_max);
|
||||
constexpr static int identifier_length_max = MAX_ID_NAME;
|
||||
static_assert(sizeof(AnimData::slot_name) == identifier_length_max);
|
||||
static_assert(sizeof(NlaStrip::action_slot_name) == identifier_length_max);
|
||||
|
||||
/**
|
||||
* Return the name prefix for the Slot's type.
|
||||
* Return the identifier prefix for the Slot's type.
|
||||
*
|
||||
* This is the ID name prefix, so "OB" for objects, "CA" for cameras, etc.
|
||||
*/
|
||||
std::string name_prefix_for_idtype() const;
|
||||
std::string identifier_prefix_for_idtype() const;
|
||||
|
||||
/**
|
||||
* Return the name without the prefix, also known as the "display name".
|
||||
* Return the identifier without the prefix, also known as the "display name".
|
||||
*
|
||||
* \see name_prefix_for_idtype
|
||||
* \see identifier_prefix_for_idtype
|
||||
*/
|
||||
StringRefNull name_without_prefix() const;
|
||||
StringRefNull identifier_without_prefix() const;
|
||||
|
||||
/** Return whether this Slot is usable by this ID type. */
|
||||
bool is_suitable_for(const ID &animated_id) const;
|
||||
@@ -710,20 +710,20 @@ class Slot : public ::ActionSlot {
|
||||
static void users_invalidate(Main &bmain);
|
||||
|
||||
/**
|
||||
* Ensure the first two characters of the name match the ID type.
|
||||
* Ensure the first two characters of the identifier match the ID type.
|
||||
*
|
||||
* This typically should not be called directly. Prefer assigning to an ID to
|
||||
* get the idtype and name prefix properly set. Prefer calling
|
||||
* `Action::slot_name_set()` if you want to set the slot name. Both of those
|
||||
* get the idtype and identifier prefix properly set. Prefer calling
|
||||
* `Action::slot_identifier_set()` if you want to set the slot identifier. Both of those
|
||||
* approaches take care of ensuring uniqueness and other invariants.
|
||||
*
|
||||
* \note This does NOT ensure name uniqueness within the Action. That is the
|
||||
* \note This does NOT ensure identifier uniqueness within the Action. That is the
|
||||
* responsibility of the caller.
|
||||
*
|
||||
* \see #assign_action_slot
|
||||
* \see #Action::slot_name_set
|
||||
* \see #Action::slot_identifier_set
|
||||
*/
|
||||
void name_ensure_prefix();
|
||||
void identifier_ensure_prefix();
|
||||
|
||||
protected:
|
||||
friend Action;
|
||||
@@ -1221,10 +1221,10 @@ ActionSlotAssignmentResult assign_action_and_slot(Action *action,
|
||||
* mode (in which case no Action assignments can happen), or when the legacy Action ID type doesn't
|
||||
* match the animated ID.
|
||||
*
|
||||
* \note Contrary to `assign_action()` this skips the search by slot name when the Action is
|
||||
* \note Contrary to `assign_action()` this skips the search by slot identifier when the Action is
|
||||
* already assigned. It should be possible for an animator to un-assign a slot, then create a new
|
||||
* slot by inserting a new key. This shouldn't auto-assign the old slot (by name) and _then_ insert
|
||||
* the key.
|
||||
* slot by inserting a new key. This shouldn't auto-assign the old slot (by identifier) and _then_
|
||||
* insert the key.
|
||||
*
|
||||
* \see assign_action()
|
||||
*/
|
||||
@@ -1267,7 +1267,7 @@ ActionSlotAssignmentResult assign_action_and_slot(Action *action,
|
||||
bAction *action_to_assign,
|
||||
bAction *&action_ptr_ref,
|
||||
slot_handle_t &slot_handle_ref,
|
||||
char *slot_name);
|
||||
char *slot_identifier);
|
||||
|
||||
/**
|
||||
* Generic function to build Slot-assignment logic.
|
||||
@@ -1279,7 +1279,7 @@ ActionSlotAssignmentResult assign_action_and_slot(Action *action,
|
||||
ID &animated_id,
|
||||
bAction *&action_ptr_ref,
|
||||
slot_handle_t &slot_handle_ref,
|
||||
char *slot_name);
|
||||
char *slot_identifier);
|
||||
|
||||
/**
|
||||
* Generic function to build Slot Handle-assignment logic.
|
||||
@@ -1292,7 +1292,7 @@ ActionSlotAssignmentResult assign_action_and_slot(Action *action,
|
||||
ID &animated_id,
|
||||
bAction *&action_ptr_ref,
|
||||
slot_handle_t &slot_handle_ref,
|
||||
char *slot_name);
|
||||
char *slot_identifier);
|
||||
|
||||
/* --------------- Accessors --------------------- */
|
||||
|
||||
@@ -1622,9 +1622,9 @@ Action *convert_to_layered_action(Main &bmain, const Action &legacy_action);
|
||||
|
||||
/**
|
||||
* Move the given slot from `from_action` to `to_action`.
|
||||
* The slot name might not be exactly the same if the name already exists in the slots of
|
||||
* `to_action`. Also the slot handle is likely going to be different on `to_action`.
|
||||
* All users of the slot will be reassigned to the moved slot on `to_action`.
|
||||
* The slot identifier might not be exactly the same if the identifier already exists in the slots
|
||||
* of `to_action`. Also the slot handle is likely going to be different on `to_action`. All users
|
||||
* of the slot will be reassigned to the moved slot on `to_action`.
|
||||
*
|
||||
* \note The `from_action` will not be deleted by this function. But it might leave it without
|
||||
* users which means it will not be saved (unless it has a fake user).
|
||||
|
||||
@@ -59,8 +59,8 @@ namespace blender::animrig {
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* Default name for action slots. The first two characters in the name indicate the ID type
|
||||
* of whatever is animated by it.
|
||||
* Default identifier for action slots. The first two characters in the identifier indicate the ID
|
||||
* type of whatever is animated by it.
|
||||
*
|
||||
* Since the ID type may not be determined when the slot is created, the prefix starts out at
|
||||
* XX. Note that no code should use this XX value; use Slot::has_idtype() instead.
|
||||
@@ -371,7 +371,7 @@ const Slot *Action::slot_for_handle(const slot_handle_t handle) const
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void slot_name_ensure_unique(Action &action, Slot &slot)
|
||||
static void slot_identifier_ensure_unique(Action &action, Slot &slot)
|
||||
{
|
||||
/* Cannot capture parameters by reference in the lambda, as that would change its signature
|
||||
* and no longer be compatible with BLI_uniquename_cb(). That's why this struct is necessary. */
|
||||
@@ -388,36 +388,38 @@ static void slot_name_ensure_unique(Action &action, Slot &slot)
|
||||
/* Don't compare against the slot that's being renamed. */
|
||||
continue;
|
||||
}
|
||||
if (STREQ(slot->name, name)) {
|
||||
if (STREQ(slot->identifier, name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
BLI_uniquename_cb(check_name_is_used, &check_data, "", '.', slot.name, sizeof(slot.name));
|
||||
BLI_uniquename_cb(
|
||||
check_name_is_used, &check_data, "", '.', slot.identifier, sizeof(slot.identifier));
|
||||
}
|
||||
|
||||
void Action::slot_name_set(Main &bmain, Slot &slot, const StringRefNull new_name)
|
||||
void Action::slot_identifier_set(Main &bmain, Slot &slot, const StringRefNull new_identifier)
|
||||
{
|
||||
/* TODO: maybe this function should only set the 'name without prefix' aka the 'display name'.
|
||||
* That way only `this->id_type` is responsible for the prefix. I (Sybren) think that's easier to
|
||||
* determine when the code is a bit more mature, and we can see what the majority of the calls to
|
||||
* this function actually do/need. */
|
||||
/* TODO: maybe this function should only set the 'identifier without prefix' aka the 'display
|
||||
* name'. That way only `this->id_type` is responsible for the prefix. I (Sybren) think that's
|
||||
* easier to determine when the code is a bit more mature, and we can see what the majority of
|
||||
* the calls to this function actually do/need. */
|
||||
|
||||
this->slot_name_define(slot, new_name);
|
||||
this->slot_name_propagate(bmain, slot);
|
||||
this->slot_identifier_define(slot, new_identifier);
|
||||
this->slot_identifier_propagate(bmain, slot);
|
||||
}
|
||||
|
||||
void Action::slot_name_define(Slot &slot, const StringRefNull new_name)
|
||||
void Action::slot_identifier_define(Slot &slot, const StringRefNull new_identifier)
|
||||
{
|
||||
BLI_assert_msg(StringRef(new_name).size() >= Slot::name_length_min,
|
||||
"Action Slots must be large enough for a 2-letter ID code + the display name");
|
||||
STRNCPY_UTF8(slot.name, new_name.c_str());
|
||||
slot_name_ensure_unique(*this, slot);
|
||||
BLI_assert_msg(
|
||||
StringRef(new_identifier).size() >= Slot::identifier_length_min,
|
||||
"Action Slot identifiers must be large enough for a 2-letter ID code + the display name");
|
||||
STRNCPY_UTF8(slot.identifier, new_identifier.c_str());
|
||||
slot_identifier_ensure_unique(*this, slot);
|
||||
}
|
||||
|
||||
void Action::slot_name_propagate(Main &bmain, const Slot &slot)
|
||||
void Action::slot_identifier_propagate(Main &bmain, const Slot &slot)
|
||||
{
|
||||
/* Just loop over all animatable IDs in the main database. */
|
||||
ListBase *lb;
|
||||
@@ -440,18 +442,18 @@ void Action::slot_name_propagate(Main &bmain, const Slot &slot)
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Ensure the Slot name on the AnimData is correct. */
|
||||
STRNCPY_UTF8(adt->slot_name, slot.name);
|
||||
/* Ensure the Slot identifier on the AnimData is correct. */
|
||||
STRNCPY_UTF8(adt->slot_name, slot.identifier);
|
||||
}
|
||||
FOREACH_MAIN_LISTBASE_ID_END;
|
||||
}
|
||||
FOREACH_MAIN_LISTBASE_END;
|
||||
}
|
||||
|
||||
Slot *Action::slot_find_by_name(const StringRefNull slot_name)
|
||||
Slot *Action::slot_find_by_identifier(const StringRefNull slot_identifier)
|
||||
{
|
||||
for (Slot *slot : slots()) {
|
||||
if (STREQ(slot->name, slot_name.c_str())) {
|
||||
if (STREQ(slot->identifier, slot_identifier.c_str())) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
@@ -476,14 +478,14 @@ Slot &Action::slot_add()
|
||||
{
|
||||
Slot &slot = this->slot_allocate();
|
||||
|
||||
/* Assign the default name and the 'unbound' name prefix. */
|
||||
STRNCPY_UTF8(slot.name, slot_unbound_prefix);
|
||||
BLI_strncpy_utf8(slot.name + 2, DATA_(slot_default_name), ARRAY_SIZE(slot.name) - 2);
|
||||
/* Assign the default name and the 'unbound' identifier prefix. */
|
||||
STRNCPY_UTF8(slot.identifier, slot_unbound_prefix);
|
||||
BLI_strncpy_utf8(slot.identifier + 2, DATA_(slot_default_name), ARRAY_SIZE(slot.identifier) - 2);
|
||||
|
||||
/* Append the Slot to the Action. */
|
||||
grow_array_and_append<::ActionSlot *>(&this->slot_array, &this->slot_array_num, &slot);
|
||||
|
||||
slot_name_ensure_unique(*this, slot);
|
||||
slot_identifier_ensure_unique(*this, slot);
|
||||
|
||||
/* If this is the first slot in this Action, it means that it could have
|
||||
* been used as a legacy Action before. As a result, this->idroot may be
|
||||
@@ -501,9 +503,9 @@ Slot &Action::slot_add_for_id(const ID &animated_id)
|
||||
Slot &slot = this->slot_add();
|
||||
|
||||
slot.idtype = GS(animated_id.name);
|
||||
this->slot_name_define(slot, animated_id.name);
|
||||
this->slot_identifier_define(slot, animated_id.name);
|
||||
|
||||
/* No need to call anim.slot_name_propagate() as nothing will be using
|
||||
/* No need to call anim.slot_identifier_propagate() as nothing will be using
|
||||
* this brand new Slot yet. */
|
||||
|
||||
return slot;
|
||||
@@ -571,9 +573,9 @@ Slot *Action::find_suitable_slot_for(const ID &animated_id)
|
||||
}
|
||||
}
|
||||
|
||||
/* Try the slot name from the AnimData, if it is set. */
|
||||
/* Try the slot identifier from the AnimData, if it is set. */
|
||||
if (adt && adt->slot_name[0]) {
|
||||
Slot *slot = this->slot_find_by_name(adt->slot_name);
|
||||
Slot *slot = this->slot_find_by_identifier(adt->slot_name);
|
||||
if (slot && slot->is_suitable_for(animated_id)) {
|
||||
return slot;
|
||||
}
|
||||
@@ -581,7 +583,7 @@ Slot *Action::find_suitable_slot_for(const ID &animated_id)
|
||||
|
||||
/* Search for the ID name (which includes the ID type). */
|
||||
{
|
||||
Slot *slot = this->slot_find_by_name(animated_id.name);
|
||||
Slot *slot = this->slot_find_by_identifier(animated_id.name);
|
||||
if (slot && slot->is_suitable_for(animated_id)) {
|
||||
return slot;
|
||||
}
|
||||
@@ -684,10 +686,10 @@ Layer *Action::get_layer_for_keyframing()
|
||||
return this->layer(0);
|
||||
}
|
||||
|
||||
void Action::slot_name_ensure_prefix(Slot &slot)
|
||||
void Action::slot_identifier_ensure_prefix(Slot &slot)
|
||||
{
|
||||
slot.name_ensure_prefix();
|
||||
slot_name_ensure_unique(*this, slot);
|
||||
slot.identifier_ensure_prefix();
|
||||
slot_identifier_ensure_unique(*this, slot);
|
||||
}
|
||||
|
||||
void Action::slot_setup_for_id(Slot &slot, const ID &animated_id)
|
||||
@@ -698,7 +700,7 @@ void Action::slot_setup_for_id(Slot &slot, const ID &animated_id)
|
||||
}
|
||||
|
||||
slot.idtype = GS(animated_id.name);
|
||||
this->slot_name_ensure_prefix(slot);
|
||||
this->slot_identifier_ensure_prefix(slot);
|
||||
}
|
||||
|
||||
bool Action::has_keyframes(const slot_handle_t action_slot_handle) const
|
||||
@@ -1112,7 +1114,7 @@ void Slot::users_invalidate(Main &bmain)
|
||||
bmain.is_action_slot_to_id_map_dirty = true;
|
||||
}
|
||||
|
||||
std::string Slot::name_prefix_for_idtype() const
|
||||
std::string Slot::identifier_prefix_for_idtype() const
|
||||
{
|
||||
if (!this->has_idtype()) {
|
||||
return slot_unbound_prefix;
|
||||
@@ -1123,35 +1125,35 @@ std::string Slot::name_prefix_for_idtype() const
|
||||
return name;
|
||||
}
|
||||
|
||||
StringRefNull Slot::name_without_prefix() const
|
||||
StringRefNull Slot::identifier_without_prefix() const
|
||||
{
|
||||
BLI_assert(StringRef(this->name).size() >= name_length_min);
|
||||
BLI_assert(StringRef(this->identifier).size() >= identifier_length_min);
|
||||
|
||||
/* Avoid accessing an uninitialized part of the string accidentally. */
|
||||
if (this->name[0] == '\0' || this->name[1] == '\0') {
|
||||
if (this->identifier[0] == '\0' || this->identifier[1] == '\0') {
|
||||
return "";
|
||||
}
|
||||
return this->name + 2;
|
||||
return this->identifier + 2;
|
||||
}
|
||||
|
||||
void Slot::name_ensure_prefix()
|
||||
void Slot::identifier_ensure_prefix()
|
||||
{
|
||||
BLI_assert(StringRef(this->name).size() >= name_length_min);
|
||||
BLI_assert(StringRef(this->identifier).size() >= identifier_length_min);
|
||||
|
||||
if (StringRef(this->name).size() < 2) {
|
||||
if (StringRef(this->identifier).size() < 2) {
|
||||
/* The code below would overwrite the trailing 0-byte. */
|
||||
this->name[2] = '\0';
|
||||
this->identifier[2] = '\0';
|
||||
}
|
||||
|
||||
if (!this->has_idtype()) {
|
||||
/* A zero idtype is not going to convert to a two-character string, so we
|
||||
* need to explicitly assign the default prefix. */
|
||||
this->name[0] = slot_unbound_prefix[0];
|
||||
this->name[1] = slot_unbound_prefix[1];
|
||||
this->identifier[0] = slot_unbound_prefix[0];
|
||||
this->identifier[1] = slot_unbound_prefix[1];
|
||||
return;
|
||||
}
|
||||
|
||||
*reinterpret_cast<short *>(this->name) = this->idtype;
|
||||
*reinterpret_cast<short *>(this->identifier) = this->idtype;
|
||||
}
|
||||
|
||||
/* ----- Functions ----------- */
|
||||
@@ -1223,13 +1225,13 @@ Slot *assign_action_ensure_slot_for_keying(Action &action, ID &animated_id)
|
||||
* re-assign an intentionally-unassigned slot. */
|
||||
}
|
||||
else {
|
||||
/* Try the slot name from the AnimData, if it is set. */
|
||||
/* Try the slot identifier from the AnimData, if it is set. */
|
||||
if (adt && adt->slot_name[0]) {
|
||||
slot = action.slot_find_by_name(adt->slot_name);
|
||||
slot = action.slot_find_by_identifier(adt->slot_name);
|
||||
}
|
||||
else {
|
||||
/* Search for the ID name (which includes the ID type). */
|
||||
slot = action.slot_find_by_name(animated_id.name);
|
||||
slot = action.slot_find_by_identifier(animated_id.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1286,9 +1288,9 @@ bool generic_assign_action(ID &animated_id,
|
||||
bAction *action_to_assign,
|
||||
bAction *&action_ptr_ref,
|
||||
slot_handle_t &slot_handle_ref,
|
||||
char *slot_name)
|
||||
char *slot_identifier)
|
||||
{
|
||||
BLI_assert(slot_name);
|
||||
BLI_assert(slot_identifier);
|
||||
|
||||
if (action_to_assign && legacy::action_treat_as_legacy(*action_to_assign)) {
|
||||
/* Check that the Action is suitable for this ID type.
|
||||
@@ -1310,7 +1312,7 @@ bool generic_assign_action(ID &animated_id,
|
||||
/* Un-assign the slot. This will always succeed, so no need to check the result. */
|
||||
if (slot_handle_ref != Slot::unassigned) {
|
||||
const ActionSlotAssignmentResult result = generic_assign_action_slot(
|
||||
nullptr, animated_id, action_ptr_ref, slot_handle_ref, slot_name);
|
||||
nullptr, animated_id, action_ptr_ref, slot_handle_ref, slot_identifier);
|
||||
BLI_assert(result == ActionSlotAssignmentResult::OK);
|
||||
UNUSED_VARS_NDEBUG(result);
|
||||
}
|
||||
@@ -1333,7 +1335,7 @@ bool generic_assign_action(ID &animated_id,
|
||||
* `nullptr`, which is perfectly acceptable for generic_assign_action_slot(). */
|
||||
Slot *slot = action_to_assign->wrap().find_suitable_slot_for(animated_id);
|
||||
const ActionSlotAssignmentResult result = generic_assign_action_slot(
|
||||
slot, animated_id, action_ptr_ref, slot_handle_ref, slot_name);
|
||||
slot, animated_id, action_ptr_ref, slot_handle_ref, slot_identifier);
|
||||
BLI_assert(result == ActionSlotAssignmentResult::OK);
|
||||
UNUSED_VARS_NDEBUG(result);
|
||||
|
||||
@@ -1344,9 +1346,9 @@ ActionSlotAssignmentResult generic_assign_action_slot(Slot *slot_to_assign,
|
||||
ID &animated_id,
|
||||
bAction *&action_ptr_ref,
|
||||
slot_handle_t &slot_handle_ref,
|
||||
char *slot_name)
|
||||
char *slot_identifier)
|
||||
{
|
||||
BLI_assert(slot_name);
|
||||
BLI_assert(slot_identifier);
|
||||
if (!action_ptr_ref) {
|
||||
/* No action assigned yet, so no way to assign a slot. */
|
||||
return ActionSlotAssignmentResult::MissingAction;
|
||||
@@ -1370,14 +1372,14 @@ ActionSlotAssignmentResult generic_assign_action_slot(Slot *slot_to_assign,
|
||||
/* If there was a previously-assigned slot, unassign it first. */
|
||||
slot_handle_ref = Slot::unassigned;
|
||||
if (slot_to_unassign) {
|
||||
/* Make sure that the stored Slot name is up to date. The slot name might have
|
||||
/* Make sure that the stored Slot identifier is up to date. The slot identifier might have
|
||||
* changed in a way that wasn't copied into the ADT yet (for example when the
|
||||
* Action is linked from another file), so better copy the name to be sure
|
||||
* Action is linked from another file), so better copy the identifier to be sure
|
||||
* that it can be transparently reassigned later.
|
||||
*
|
||||
* TODO: Replace this with a BLI_assert() that the name is as expected, and "simply" ensure
|
||||
* this name is always correct. */
|
||||
BLI_strncpy_utf8(slot_name, slot_to_unassign->name, Slot::name_length_max);
|
||||
* TODO: Replace this with a BLI_assert() that the identifier is as expected, and "simply"
|
||||
* ensure this identifier is always correct. */
|
||||
BLI_strncpy_utf8(slot_identifier, slot_to_unassign->identifier, Slot::identifier_length_max);
|
||||
|
||||
/* If this was the last use of this slot, remove this ID from its users. */
|
||||
if (!is_id_using_action_slot(animated_id, action, slot_to_unassign->handle)) {
|
||||
@@ -1391,7 +1393,7 @@ ActionSlotAssignmentResult generic_assign_action_slot(Slot *slot_to_assign,
|
||||
|
||||
action.slot_setup_for_id(*slot_to_assign, animated_id);
|
||||
slot_handle_ref = slot_to_assign->handle;
|
||||
BLI_strncpy_utf8(slot_name, slot_to_assign->name, Slot::name_length_max);
|
||||
BLI_strncpy_utf8(slot_identifier, slot_to_assign->identifier, Slot::identifier_length_max);
|
||||
slot_to_assign->users_add(animated_id);
|
||||
|
||||
return ActionSlotAssignmentResult::OK;
|
||||
@@ -1401,7 +1403,7 @@ ActionSlotAssignmentResult generic_assign_action_slot_handle(slot_handle_t slot_
|
||||
ID &animated_id,
|
||||
bAction *&action_ptr_ref,
|
||||
slot_handle_t &slot_handle_ref,
|
||||
char *slot_name)
|
||||
char *slot_identifier)
|
||||
{
|
||||
if (slot_handle_to_assign == Slot::unassigned && !action_ptr_ref) {
|
||||
/* No Action assigned, so no slot was used anyway. Just blindly assign the
|
||||
@@ -1418,7 +1420,8 @@ ActionSlotAssignmentResult generic_assign_action_slot_handle(slot_handle_t slot_
|
||||
}
|
||||
|
||||
Slot *slot = action_ptr_ref->wrap().slot_for_handle(slot_handle_to_assign);
|
||||
return generic_assign_action_slot(slot, animated_id, action_ptr_ref, slot_handle_ref, slot_name);
|
||||
return generic_assign_action_slot(
|
||||
slot, animated_id, action_ptr_ref, slot_handle_ref, slot_identifier);
|
||||
}
|
||||
|
||||
bool is_action_assignable_to(const bAction *dna_action, const ID_Type id_code)
|
||||
@@ -1957,7 +1960,7 @@ SingleKeyingResult StripKeyframeData::keyframe_insert(Main *bmain,
|
||||
"Available setting or Replace keyframing mode.\n",
|
||||
fcurve_descriptor.rna_path.c_str(),
|
||||
fcurve_descriptor.array_index,
|
||||
slot.name);
|
||||
slot.identifier);
|
||||
return SingleKeyingResult::CANNOT_CREATE_FCURVE;
|
||||
}
|
||||
|
||||
@@ -1967,7 +1970,7 @@ SingleKeyingResult StripKeyframeData::keyframe_insert(Main *bmain,
|
||||
"FCurve %s[%d] for slot %s doesn't allow inserting keys.\n",
|
||||
fcurve_descriptor.rna_path.c_str(),
|
||||
fcurve_descriptor.array_index,
|
||||
slot.name);
|
||||
slot.identifier);
|
||||
return SingleKeyingResult::FCURVE_NOT_KEYFRAMEABLE;
|
||||
}
|
||||
|
||||
@@ -1994,7 +1997,7 @@ SingleKeyingResult StripKeyframeData::keyframe_insert(Main *bmain,
|
||||
"Could not insert key into FCurve %s[%d] for slot %s.\n",
|
||||
fcurve_descriptor.rna_path.c_str(),
|
||||
fcurve_descriptor.array_index,
|
||||
slot.name);
|
||||
slot.identifier);
|
||||
return insert_vert_result;
|
||||
}
|
||||
|
||||
@@ -2924,8 +2927,8 @@ Action *convert_to_layered_action(Main &bmain, const Action &legacy_action)
|
||||
|
||||
/**
|
||||
* Clone information from the given slot into this slot while retaining important info like the
|
||||
* slot handle and runtime data. This copies the name which might clash with other names on the
|
||||
* action. Call `slot_name_ensure_unique` after.
|
||||
* slot handle and runtime data. This copies the identifier which might clash with other
|
||||
* identifiers on the action. Call `slot_name_ensure_unique` after.
|
||||
*/
|
||||
static void clone_slot(Slot &from, Slot &to)
|
||||
{
|
||||
@@ -2952,7 +2955,7 @@ void move_slot(Main &bmain, Slot &source_slot, Action &from_action, Action &to_a
|
||||
|
||||
Slot &target_slot = to_action.slot_add();
|
||||
clone_slot(source_slot, target_slot);
|
||||
slot_name_ensure_unique(to_action, target_slot);
|
||||
slot_identifier_ensure_unique(to_action, target_slot);
|
||||
|
||||
ChannelBag *channel_bag = from_strip_data.channelbag_for_slot(source_slot.handle);
|
||||
BLI_assert(channel_bag != nullptr);
|
||||
@@ -2968,7 +2971,7 @@ void move_slot(Main &bmain, Slot &source_slot, Action &from_action, Action &to_a
|
||||
const auto assign_other_action = [&](ID & /* animated_id */,
|
||||
bAction *&action_ptr_ref,
|
||||
slot_handle_t &slot_handle_ref,
|
||||
char *slot_name) -> bool {
|
||||
char *slot_identifier) -> bool {
|
||||
/* Only reassign if the reference is actually from the same action. Could be from a different
|
||||
* action when using the NLA or action constraints. */
|
||||
if (action_ptr_ref != &from_action) {
|
||||
@@ -2977,13 +2980,13 @@ void move_slot(Main &bmain, Slot &source_slot, Action &from_action, Action &to_a
|
||||
|
||||
{ /* Assign the Action. */
|
||||
const bool assign_ok = generic_assign_action(
|
||||
*user, &to_action, action_ptr_ref, slot_handle_ref, slot_name);
|
||||
*user, &to_action, action_ptr_ref, slot_handle_ref, slot_identifier);
|
||||
BLI_assert_msg(assign_ok, "Expecting slotted Actions to always be assignable");
|
||||
UNUSED_VARS_NDEBUG(assign_ok);
|
||||
}
|
||||
{ /* Assign the Slot. */
|
||||
const ActionSlotAssignmentResult result = generic_assign_action_slot(
|
||||
&target_slot, *user, action_ptr_ref, slot_handle_ref, slot_name);
|
||||
&target_slot, *user, action_ptr_ref, slot_handle_ref, slot_identifier);
|
||||
BLI_assert(result == ActionSlotAssignmentResult::OK);
|
||||
UNUSED_VARS_NDEBUG(result);
|
||||
}
|
||||
|
||||
@@ -152,7 +152,8 @@ TEST_F(ActionIteratorsTest, foreach_action_slot_use_with_references)
|
||||
<< "Expected Action " << other_action.id.name << " but found "
|
||||
<< action_and_slot->first->id.name;
|
||||
EXPECT_EQ(&another_slot, action_and_slot->second)
|
||||
<< "Expected Slot " << another_slot.name << " but found " << action_and_slot->second->name;
|
||||
<< "Expected Slot " << another_slot.identifier << " but found "
|
||||
<< action_and_slot->second->identifier;
|
||||
}
|
||||
|
||||
} // namespace blender::animrig::tests
|
||||
|
||||
@@ -278,7 +278,7 @@ TEST_F(ActionLayersTest, add_slot)
|
||||
EXPECT_EQ(1, action->last_slot_handle);
|
||||
EXPECT_EQ(1, slot.handle);
|
||||
|
||||
EXPECT_STREQ("XXSlot", slot.name);
|
||||
EXPECT_STREQ("XXSlot", slot.identifier);
|
||||
EXPECT_EQ(0, slot.idtype);
|
||||
}
|
||||
|
||||
@@ -287,7 +287,7 @@ TEST_F(ActionLayersTest, add_slot)
|
||||
EXPECT_EQ(2, action->last_slot_handle);
|
||||
EXPECT_EQ(2, slot.handle);
|
||||
|
||||
EXPECT_STREQ(cube->id.name, slot.name);
|
||||
EXPECT_STREQ(cube->id.name, slot.identifier);
|
||||
EXPECT_EQ(ID_OB, slot.idtype);
|
||||
}
|
||||
}
|
||||
@@ -425,13 +425,13 @@ TEST_F(ActionLayersTest, action_assign_id)
|
||||
/* Assign to the only, 'virgin' Slot, should always work. */
|
||||
Slot &slot_cube = action->slot_add();
|
||||
ASSERT_NE(nullptr, slot_cube.runtime);
|
||||
ASSERT_STREQ(slot_cube.name, "XXSlot");
|
||||
ASSERT_STREQ(slot_cube.identifier, "XXSlot");
|
||||
ASSERT_EQ(assign_action_and_slot(action, &slot_cube, cube->id), ActionSlotAssignmentResult::OK);
|
||||
|
||||
EXPECT_EQ(slot_cube.handle, cube->adt->slot_handle);
|
||||
EXPECT_STREQ(slot_cube.name, "OBSlot");
|
||||
EXPECT_STREQ(slot_cube.name, cube->adt->slot_name)
|
||||
<< "The slot name should be copied to the adt";
|
||||
EXPECT_STREQ(slot_cube.identifier, "OBSlot");
|
||||
EXPECT_STREQ(slot_cube.identifier, cube->adt->slot_name)
|
||||
<< "The slot identifier should be copied to the adt";
|
||||
|
||||
EXPECT_TRUE(slot_cube.users(*bmain).contains(&cube->id))
|
||||
<< "Expecting Cube to be registered as animated by its slot.";
|
||||
@@ -439,9 +439,9 @@ TEST_F(ActionLayersTest, action_assign_id)
|
||||
/* Assign another ID to the same Slot. */
|
||||
ASSERT_EQ(assign_action_and_slot(action, &slot_cube, suzanne->id),
|
||||
ActionSlotAssignmentResult::OK);
|
||||
EXPECT_STREQ(slot_cube.name, "OBSlot");
|
||||
EXPECT_STREQ(slot_cube.name, cube->adt->slot_name)
|
||||
<< "The slot name should be copied to the adt";
|
||||
EXPECT_STREQ(slot_cube.identifier, "OBSlot");
|
||||
EXPECT_STREQ(slot_cube.identifier, cube->adt->slot_name)
|
||||
<< "The slot identifier should be copied to the adt";
|
||||
|
||||
EXPECT_TRUE(slot_cube.users(*bmain).contains(&cube->id))
|
||||
<< "Expecting Suzanne to be registered as animated by the Cube slot.";
|
||||
@@ -492,7 +492,7 @@ TEST_F(ActionLayersTest, action_assign_id)
|
||||
ASSERT_EQ(assign_action_and_slot(action, &another_slot_cube, cube->id),
|
||||
ActionSlotAssignmentResult::OK);
|
||||
EXPECT_EQ(another_slot_cube.handle, cube->adt->slot_handle);
|
||||
EXPECT_STREQ("OBSlot.002", another_slot_cube.name) << "The slot should be uniquely named";
|
||||
EXPECT_STREQ("OBSlot.002", another_slot_cube.identifier) << "The slot should be uniquely named";
|
||||
EXPECT_STREQ("OBSlot.002", cube->adt->slot_name) << "The slot name should be copied to the adt";
|
||||
EXPECT_TRUE(another_slot_cube.users(*bmain).contains(&cube->id))
|
||||
<< "Expecting Cube to be registered as animated by the 'another_slot_cube' slot.";
|
||||
@@ -512,82 +512,82 @@ TEST_F(ActionLayersTest, rename_slot)
|
||||
Slot &slot_cube = action->slot_add();
|
||||
ASSERT_EQ(assign_action_and_slot(action, &slot_cube, cube->id), ActionSlotAssignmentResult::OK);
|
||||
EXPECT_EQ(slot_cube.handle, cube->adt->slot_handle);
|
||||
EXPECT_STREQ("OBSlot", slot_cube.name);
|
||||
EXPECT_STREQ(slot_cube.name, cube->adt->slot_name)
|
||||
<< "The slot name should be copied to the adt";
|
||||
EXPECT_STREQ("OBSlot", slot_cube.identifier);
|
||||
EXPECT_STREQ(slot_cube.identifier, cube->adt->slot_name)
|
||||
<< "The slot identifier should be copied to the adt";
|
||||
|
||||
action->slot_name_define(slot_cube, "New Slot Name");
|
||||
EXPECT_STREQ("New Slot Name", slot_cube.name);
|
||||
/* At this point the slot name will not have been copied to the cube
|
||||
action->slot_identifier_define(slot_cube, "New Slot Name");
|
||||
EXPECT_STREQ("New Slot Name", slot_cube.identifier);
|
||||
/* At this point the slot identifier will not have been copied to the cube
|
||||
* AnimData. However, I don't want to test for that here, as it's not exactly
|
||||
* desirable behavior, but more of a side-effect of the current
|
||||
* implementation. */
|
||||
|
||||
action->slot_name_propagate(*bmain, slot_cube);
|
||||
action->slot_identifier_propagate(*bmain, slot_cube);
|
||||
EXPECT_STREQ("New Slot Name", cube->adt->slot_name);
|
||||
|
||||
/* Finally, do another rename, do NOT call the propagate function, then
|
||||
* unassign. This should still result in the correct slot name being stored
|
||||
* on the ADT. */
|
||||
action->slot_name_define(slot_cube, "Even Newer Name");
|
||||
action->slot_identifier_define(slot_cube, "Even Newer Name");
|
||||
EXPECT_TRUE(unassign_action(cube->id));
|
||||
EXPECT_STREQ("Even Newer Name", cube->adt->slot_name);
|
||||
}
|
||||
|
||||
TEST_F(ActionLayersTest, slot_name_ensure_prefix)
|
||||
TEST_F(ActionLayersTest, slot_identifier_ensure_prefix)
|
||||
{
|
||||
class AccessibleSlot : public Slot {
|
||||
public:
|
||||
void name_ensure_prefix()
|
||||
void identifier_ensure_prefix()
|
||||
{
|
||||
Slot::name_ensure_prefix();
|
||||
Slot::identifier_ensure_prefix();
|
||||
}
|
||||
};
|
||||
|
||||
Slot &raw_slot = action->slot_add();
|
||||
AccessibleSlot &slot = static_cast<AccessibleSlot &>(raw_slot);
|
||||
ASSERT_STREQ("XXSlot", slot.name);
|
||||
ASSERT_STREQ("XXSlot", slot.identifier);
|
||||
ASSERT_EQ(0, slot.idtype);
|
||||
|
||||
/* Check defaults, idtype zeroed. */
|
||||
slot.name_ensure_prefix();
|
||||
EXPECT_STREQ("XXSlot", slot.name);
|
||||
slot.identifier_ensure_prefix();
|
||||
EXPECT_STREQ("XXSlot", slot.identifier);
|
||||
|
||||
/* idtype CA, default name. */
|
||||
slot.idtype = ID_CA;
|
||||
slot.name_ensure_prefix();
|
||||
EXPECT_STREQ("CASlot", slot.name);
|
||||
slot.identifier_ensure_prefix();
|
||||
EXPECT_STREQ("CASlot", slot.identifier);
|
||||
|
||||
/* idtype ME, explicit name of other idtype. */
|
||||
action->slot_name_define(slot, "CANewName");
|
||||
action->slot_identifier_define(slot, "CANewName");
|
||||
slot.idtype = ID_ME;
|
||||
slot.name_ensure_prefix();
|
||||
EXPECT_STREQ("MENewName", slot.name);
|
||||
slot.identifier_ensure_prefix();
|
||||
EXPECT_STREQ("MENewName", slot.identifier);
|
||||
|
||||
/* Zeroing out idtype. */
|
||||
slot.idtype = 0;
|
||||
slot.name_ensure_prefix();
|
||||
EXPECT_STREQ("XXNewName", slot.name);
|
||||
slot.identifier_ensure_prefix();
|
||||
EXPECT_STREQ("XXNewName", slot.identifier);
|
||||
}
|
||||
|
||||
TEST_F(ActionLayersTest, slot_name_prefix)
|
||||
TEST_F(ActionLayersTest, slot_identifier_prefix)
|
||||
{
|
||||
Slot &slot = action->slot_add();
|
||||
EXPECT_EQ("XX", slot.name_prefix_for_idtype());
|
||||
EXPECT_EQ("XX", slot.identifier_prefix_for_idtype());
|
||||
|
||||
slot.idtype = ID_CA;
|
||||
EXPECT_EQ("CA", slot.name_prefix_for_idtype());
|
||||
EXPECT_EQ("CA", slot.identifier_prefix_for_idtype());
|
||||
}
|
||||
|
||||
TEST_F(ActionLayersTest, rename_slot_name_collision)
|
||||
TEST_F(ActionLayersTest, rename_slot_identifier_collision)
|
||||
{
|
||||
Slot &slot1 = action->slot_add();
|
||||
Slot &slot2 = action->slot_add();
|
||||
|
||||
action->slot_name_define(slot1, "New Slot Name");
|
||||
action->slot_name_define(slot2, "New Slot Name");
|
||||
EXPECT_STREQ("New Slot Name", slot1.name);
|
||||
EXPECT_STREQ("New Slot Name.001", slot2.name);
|
||||
action->slot_identifier_define(slot1, "New Slot Name");
|
||||
action->slot_identifier_define(slot2, "New Slot Name");
|
||||
EXPECT_STREQ("New Slot Name", slot1.identifier);
|
||||
EXPECT_STREQ("New Slot Name.001", slot2.identifier);
|
||||
}
|
||||
|
||||
TEST_F(ActionLayersTest, find_suitable_slot)
|
||||
@@ -601,14 +601,14 @@ TEST_F(ActionLayersTest, find_suitable_slot)
|
||||
* These should nevertheless be matched up. */
|
||||
Slot &slot = action->slot_add();
|
||||
slot.handle = 327;
|
||||
STRNCPY_UTF8(slot.name, "OBKüüübus");
|
||||
STRNCPY_UTF8(slot.identifier, "OBKüüübus");
|
||||
slot.idtype = GS(cube->id.name);
|
||||
EXPECT_EQ(&slot, action->find_suitable_slot_for(cube->id));
|
||||
|
||||
/* ===
|
||||
* Slot exists with the same name & type as the ID, and the ID has an AnimData with the same
|
||||
* slot name, but a different slot_handle. Since the Action has not yet been
|
||||
* assigned to this ID, the slot_handle should be ignored, and the slot name used for
|
||||
* slot identifier, but a different slot_handle. Since the Action has not yet been
|
||||
* assigned to this ID, the slot_handle should be ignored, and the slot identifier used for
|
||||
* matching. */
|
||||
|
||||
/* Create a slot with a handle that should be ignored.*/
|
||||
@@ -617,13 +617,13 @@ TEST_F(ActionLayersTest, find_suitable_slot)
|
||||
|
||||
AnimData *adt = BKE_animdata_ensure_id(&cube->id);
|
||||
adt->action = nullptr;
|
||||
/* Configure adt to use the handle of one slot, and the name of the other. */
|
||||
/* Configure adt to use the handle of one slot, and the identifier of the other. */
|
||||
adt->slot_handle = other_slot.handle;
|
||||
STRNCPY_UTF8(adt->slot_name, slot.name);
|
||||
STRNCPY_UTF8(adt->slot_name, slot.identifier);
|
||||
EXPECT_EQ(&slot, action->find_suitable_slot_for(cube->id));
|
||||
|
||||
/* ===
|
||||
* Same situation as above (AnimData has name of one slot, but the handle of another),
|
||||
* Same situation as above (AnimData has identifier of one slot, but the handle of another),
|
||||
* except that the Action has already been assigned. In this case the handle should take
|
||||
* precedence. */
|
||||
adt->action = action;
|
||||
|
||||
@@ -205,8 +205,8 @@ TEST_F(KeyframingTest, insert_keyframes__layered_action__non_array_property)
|
||||
* to the object. */
|
||||
ASSERT_EQ(1, action.slots().size());
|
||||
Slot *slot = action.slot(0);
|
||||
EXPECT_STREQ(object->id.name, slot->name);
|
||||
EXPECT_STREQ(object->adt->slot_name, slot->name);
|
||||
EXPECT_STREQ(object->id.name, slot->identifier);
|
||||
EXPECT_STREQ(object->adt->slot_name, slot->identifier);
|
||||
EXPECT_EQ(object->adt->slot_handle, slot->handle);
|
||||
|
||||
/* We have the default layer and strip. */
|
||||
@@ -615,8 +615,8 @@ TEST_F(KeyframingTest, insert_keyframes__layered_action__multiple_ids)
|
||||
ASSERT_EQ(1, action.slots().size());
|
||||
Slot *slot_1 = action.slot_for_handle(object->adt->slot_handle);
|
||||
ASSERT_NE(nullptr, slot_1);
|
||||
EXPECT_STREQ(object->id.name, slot_1->name);
|
||||
EXPECT_STREQ(object->adt->slot_name, slot_1->name);
|
||||
EXPECT_STREQ(object->id.name, slot_1->identifier);
|
||||
EXPECT_STREQ(object->adt->slot_name, slot_1->identifier);
|
||||
|
||||
/* Get the keyframe strip. */
|
||||
ASSERT_TRUE(action.is_action_layered());
|
||||
@@ -648,8 +648,8 @@ TEST_F(KeyframingTest, insert_keyframes__layered_action__multiple_ids)
|
||||
ASSERT_EQ(2, action.slots().size());
|
||||
Slot *slot_2 = action.slot_for_handle(armature_object->adt->slot_handle);
|
||||
ASSERT_NE(nullptr, slot_2);
|
||||
EXPECT_STREQ(armature_object->id.name, slot_2->name);
|
||||
EXPECT_STREQ(armature_object->adt->slot_name, slot_2->name);
|
||||
EXPECT_STREQ(armature_object->id.name, slot_2->identifier);
|
||||
EXPECT_STREQ(armature_object->adt->slot_name, slot_2->identifier);
|
||||
|
||||
ASSERT_EQ(2, strip_data->channelbags().size());
|
||||
ChannelBag *channel_bag_2 = strip_data->channelbag_for_slot(*slot_2);
|
||||
|
||||
@@ -87,7 +87,7 @@ TEST_F(NLASlottedActionTest, assign_slot_to_nla_strip)
|
||||
/* Assign the Action. */
|
||||
EXPECT_TRUE(nla::assign_action(*strip, *action, cube->id));
|
||||
EXPECT_EQ(strip->action_slot_handle, virgin_slot.handle);
|
||||
EXPECT_STREQ(strip->action_slot_name, virgin_slot.name);
|
||||
EXPECT_STREQ(strip->action_slot_name, virgin_slot.identifier);
|
||||
EXPECT_EQ(action->id.us, 1);
|
||||
EXPECT_EQ(strip->act, action);
|
||||
EXPECT_EQ(virgin_slot.idtype, GS(cube->id.name));
|
||||
@@ -101,7 +101,7 @@ TEST_F(NLASlottedActionTest, assign_slot_to_nla_strip)
|
||||
Slot &slot = action->slot_add_for_id(cube->id);
|
||||
EXPECT_TRUE(nla::assign_action(*strip, *action, cube->id));
|
||||
EXPECT_EQ(strip->action_slot_handle, slot.handle);
|
||||
EXPECT_STREQ(strip->action_slot_name, slot.name);
|
||||
EXPECT_STREQ(strip->action_slot_name, slot.identifier);
|
||||
EXPECT_EQ(action->id.us, 1);
|
||||
EXPECT_EQ(strip->act, action);
|
||||
EXPECT_TRUE(slot.runtime_users().contains(&cube->id));
|
||||
@@ -109,7 +109,7 @@ TEST_F(NLASlottedActionTest, assign_slot_to_nla_strip)
|
||||
/* Unassign the slot, but keep the Action assigned. */
|
||||
EXPECT_EQ(nla::assign_action_slot(*strip, nullptr, cube->id), ActionSlotAssignmentResult::OK);
|
||||
EXPECT_EQ(strip->action_slot_handle, Slot::unassigned);
|
||||
EXPECT_STREQ(strip->action_slot_name, slot.name);
|
||||
EXPECT_STREQ(strip->action_slot_name, slot.identifier);
|
||||
EXPECT_EQ(action->id.us, 1);
|
||||
EXPECT_EQ(strip->act, action);
|
||||
EXPECT_FALSE(slot.runtime_users().contains(&cube->id));
|
||||
@@ -146,7 +146,7 @@ TEST_F(NLASlottedActionTest, assign_slot_to_multiple_strips)
|
||||
Slot &slot = action->slot_add();
|
||||
EXPECT_TRUE(nla::assign_action(*strip1, *action, cube->id));
|
||||
EXPECT_EQ(strip1->action_slot_handle, slot.handle);
|
||||
EXPECT_STREQ(strip1->action_slot_name, slot.name);
|
||||
EXPECT_STREQ(strip1->action_slot_name, slot.identifier);
|
||||
EXPECT_EQ(slot.idtype, ID_OB);
|
||||
|
||||
/* Assign another slot slot 'manually'. */
|
||||
|
||||
@@ -6695,5 +6695,5 @@ void BKE_constraint_blend_read_data(BlendDataReader *reader, ID *id_owner, ListB
|
||||
* inclusion of an DNA_anim_types.h in DNA_constraint_types.h just for this assert. */
|
||||
static_assert(
|
||||
std::is_same_v<decltype(ActionSlot::handle), decltype(bActionConstraint::action_slot_handle)>);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(ActionSlot::name), decltype(bActionConstraint::action_slot_name)>);
|
||||
static_assert(std::is_same_v<decltype(ActionSlot::identifier),
|
||||
decltype(bActionConstraint::action_slot_name)>);
|
||||
|
||||
@@ -2387,7 +2387,7 @@ bool BKE_nla_tweakmode_enter(const OwnedAnimData owned_adt)
|
||||
animrig::ActionSlotAssignmentResult::OK)
|
||||
{
|
||||
printf("NLA tweak-mode enter - could not assign slot %s\n",
|
||||
strip_slot ? strip_slot->name : "-unassigned-");
|
||||
strip_slot ? strip_slot->identifier : "-unassigned-");
|
||||
/* There is one other reason this could fail: when already in NLA tweak mode. But since
|
||||
* we're here in the code, the ADT_NLA_EDIT_ON flag is not yet set, and thus that shouldn't
|
||||
* be the case.
|
||||
|
||||
@@ -131,7 +131,7 @@ static void convert_action_in_place(blender::animrig::Action &action)
|
||||
|
||||
Slot &slot = action.slot_add();
|
||||
slot.idtype = idtype;
|
||||
slot.name_ensure_prefix();
|
||||
slot.identifier_ensure_prefix();
|
||||
|
||||
Layer &layer = action.layer_add("Layer");
|
||||
blender::animrig::Strip &strip = layer.strip_add(action,
|
||||
@@ -248,7 +248,7 @@ static void version_legacy_actions_to_layered(Main *bmain)
|
||||
if (user_infos.size() == 1) {
|
||||
/* Rename the slot after its single user. If there are multiple users, the name is unchanged
|
||||
* because there is no good way to determine a name. */
|
||||
action.slot_name_set(*bmain, slot_to_assign, user_infos[0].id->name);
|
||||
action.slot_identifier_set(*bmain, slot_to_assign, user_infos[0].id->name);
|
||||
}
|
||||
for (ActionUserInfo &action_user : user_infos) {
|
||||
const ActionSlotAssignmentResult result = generic_assign_action_slot(
|
||||
@@ -270,7 +270,8 @@ static void version_legacy_actions_to_layered(Main *bmain)
|
||||
* preserve this unusual (but technically valid) state of affairs.
|
||||
*/
|
||||
*action_user.slot_handle = slot_to_assign.handle;
|
||||
BLI_strncpy_utf8(action_user.slot_name, slot_to_assign.name, Slot::name_length_max);
|
||||
BLI_strncpy_utf8(
|
||||
action_user.slot_name, slot_to_assign.identifier, Slot::identifier_length_max);
|
||||
|
||||
printf(
|
||||
"Warning: legacy action \"%s\" is assigned to \"%s\", which does not match the "
|
||||
@@ -279,9 +280,9 @@ static void version_legacy_actions_to_layered(Main *bmain)
|
||||
"this type mismatch. This likely indicates something odd about the blend file.\n",
|
||||
action.id.name + 2,
|
||||
action_user.id->name,
|
||||
slot_to_assign.name_prefix_for_idtype().c_str(),
|
||||
slot_to_assign.name_without_prefix().c_str(),
|
||||
slot_to_assign.name_prefix_for_idtype().c_str(),
|
||||
slot_to_assign.identifier_prefix_for_idtype().c_str(),
|
||||
slot_to_assign.identifier_without_prefix().c_str(),
|
||||
slot_to_assign.identifier_prefix_for_idtype().c_str(),
|
||||
action_user.id->name);
|
||||
break;
|
||||
case ActionSlotAssignmentResult::SlotNotFromAction:
|
||||
|
||||
@@ -1416,7 +1416,7 @@ static void acf_action_slot_name(bAnimListElem *ale, char *r_name)
|
||||
|
||||
BLI_assert(ale->bmain);
|
||||
const int num_users = slot->users(*ale->bmain).size();
|
||||
const char *display_name = slot->name_without_prefix().c_str();
|
||||
const char *display_name = slot->identifier_without_prefix().c_str();
|
||||
|
||||
BLI_assert(num_users >= 0);
|
||||
switch (num_users) {
|
||||
|
||||
@@ -5244,7 +5244,7 @@ static int slot_channels_move_to_new_action_exec(bContext *C, wmOperator * /* op
|
||||
Main *bmain = CTX_data_main(C);
|
||||
if (slots.size() == 1) {
|
||||
char actname[MAX_ID_NAME - 2];
|
||||
SNPRINTF(actname, DATA_("%sAction"), slots[0].first->name + 2);
|
||||
SNPRINTF(actname, DATA_("%sAction"), slots[0].first->identifier + 2);
|
||||
target_action = &action_add(*bmain, actname);
|
||||
}
|
||||
else {
|
||||
@@ -5311,7 +5311,7 @@ static int separate_slots_exec(bContext *C, wmOperator * /* op */)
|
||||
while (action->slot_array_num) {
|
||||
Slot *slot = action->slot(action->slot_array_num - 1);
|
||||
char actname[MAX_ID_NAME - 2];
|
||||
SNPRINTF(actname, DATA_("%sAction"), slot->name + 2);
|
||||
SNPRINTF(actname, DATA_("%sAction"), slot->identifier + 2);
|
||||
Action &target_action = action_add(*bmain, actname);
|
||||
Layer &layer = target_action.layer_add(std::nullopt);
|
||||
layer.strip_add(target_action, Strip::Type::Keyframe);
|
||||
|
||||
@@ -792,7 +792,7 @@ static int convert_action_exec(bContext *C, wmOperator * /*op*/)
|
||||
|
||||
BLI_assert(layered_action->slots().size() == 1);
|
||||
animrig::Slot *slot = layered_action->slot(0);
|
||||
layered_action->slot_name_set(*bmain, *slot, object->id.name);
|
||||
layered_action->slot_identifier_set(*bmain, *slot, object->id.name);
|
||||
|
||||
const animrig::ActionSlotAssignmentResult result = animrig::assign_action_slot(slot, object->id);
|
||||
BLI_assert(result == animrig::ActionSlotAssignmentResult::OK);
|
||||
|
||||
@@ -1162,26 +1162,38 @@ typedef struct ActionLayer {
|
||||
*/
|
||||
typedef struct ActionSlot {
|
||||
/**
|
||||
* Typically the ID name this slot was created for, including the two
|
||||
* letters indicating the ID type.
|
||||
* The string identifier of this Slot within the Action.
|
||||
*
|
||||
* The first two characters are the two-letter code corresponding to `idtype`
|
||||
* below (e.g. 'OB', 'ME', 'LA'), and the remaining characters store slot's
|
||||
* display name. Since the combination of the `idtype` and display name are
|
||||
* always unique within an action, this string identifier is as well.
|
||||
*
|
||||
* Typically this matches the ID name this slot was created for, including the
|
||||
* two letters indicating the ID type.
|
||||
*
|
||||
* \see #AnimData::slot_name
|
||||
*/
|
||||
char name[66]; /* MAX_ID_NAME */
|
||||
char identifier[66]; /* MAX_ID_NAME */
|
||||
|
||||
/**
|
||||
* Type of ID-blocks that this slot can be assigned to.
|
||||
* Type of ID-block that this slot is intended for.
|
||||
*
|
||||
* If 0, will be set to whatever ID is first assigned.
|
||||
*/
|
||||
int16_t idtype;
|
||||
|
||||
/**
|
||||
* Identifier of this Slot within the Action.
|
||||
* Numeric identifier of this Slot within the Action.
|
||||
*
|
||||
* This number allows reorganization of the #bAction::slot_array without
|
||||
* invalidating references. Also these remain valid when copy-on-evaluate
|
||||
* copies are made.
|
||||
*
|
||||
* Unlike `identifier` above, this cannot be set by the user and never changes
|
||||
* after initial assignment, and thus serves as a "forever" identifier of the
|
||||
* slot.
|
||||
*
|
||||
* Only valid within the Action that owns this Slot.
|
||||
*
|
||||
* NOTE: keep this type in sync with `slot_handle_t` in BKE_action.hh.
|
||||
|
||||
@@ -1219,7 +1219,7 @@ typedef struct AnimData {
|
||||
#ifdef __cplusplus
|
||||
/* Some static assertions that things that should have the same type actually do. */
|
||||
static_assert(std::is_same_v<decltype(ActionSlot::handle), decltype(AnimData::slot_handle)>);
|
||||
static_assert(std::is_same_v<decltype(ActionSlot::name), decltype(AnimData::slot_name)>);
|
||||
static_assert(std::is_same_v<decltype(ActionSlot::identifier), decltype(AnimData::slot_name)>);
|
||||
#endif
|
||||
|
||||
/* Animation Data settings (mostly for NLA) */
|
||||
|
||||
@@ -47,6 +47,7 @@ DNA_STRUCT_RENAME(SeqRetimingHandle, SeqRetimingKey)
|
||||
DNA_STRUCT_RENAME(SpaceButs, SpaceProperties)
|
||||
DNA_STRUCT_RENAME(SpaceIpo, SpaceGraph)
|
||||
DNA_STRUCT_RENAME(SpaceOops, SpaceOutliner)
|
||||
DNA_STRUCT_RENAME_MEMBER(ActionSlot, name, identifier)
|
||||
DNA_STRUCT_RENAME_MEMBER(BPoint, alfa, tilt)
|
||||
DNA_STRUCT_RENAME_MEMBER(BezTriple, alfa, tilt)
|
||||
DNA_STRUCT_RENAME_MEMBER(Bone, curveInX, curve_in_x)
|
||||
|
||||
@@ -296,9 +296,9 @@ static std::optional<std::string> rna_ActionSlot_path(const PointerRNA *ptr)
|
||||
{
|
||||
animrig::Slot &slot = rna_data_slot(ptr);
|
||||
|
||||
char name_esc[sizeof(slot.name) * 2];
|
||||
BLI_str_escape(name_esc, slot.name, sizeof(name_esc));
|
||||
return fmt::format("slots[\"{}\"]", name_esc);
|
||||
char identifier_esc[sizeof(slot.identifier) * 2];
|
||||
BLI_str_escape(identifier_esc, slot.identifier, sizeof(identifier_esc));
|
||||
return fmt::format("slots[\"{}\"]", identifier_esc);
|
||||
}
|
||||
|
||||
int rna_ActionSlot_id_root_icon_get(PointerRNA *ptr)
|
||||
@@ -311,13 +311,13 @@ int rna_ActionSlot_id_root_icon_get(PointerRNA *ptr)
|
||||
void rna_ActionSlot_name_display_get(PointerRNA *ptr, char *value)
|
||||
{
|
||||
animrig::Slot &slot = rna_data_slot(ptr);
|
||||
slot.name_without_prefix().unsafe_copy(value);
|
||||
slot.identifier_without_prefix().unsafe_copy(value);
|
||||
}
|
||||
|
||||
int rna_ActionSlot_name_display_length(PointerRNA *ptr)
|
||||
{
|
||||
animrig::Slot &slot = rna_data_slot(ptr);
|
||||
return slot.name_without_prefix().size();
|
||||
return slot.identifier_without_prefix().size();
|
||||
}
|
||||
|
||||
static void rna_ActionSlot_name_display_set(PointerRNA *ptr, const char *name)
|
||||
@@ -332,42 +332,43 @@ static void rna_ActionSlot_name_display_set(PointerRNA *ptr, const char *name)
|
||||
}
|
||||
|
||||
/* Construct the new internal name, from the slot's type and the given name. */
|
||||
const std::string internal_name = slot.name_prefix_for_idtype() + name_ref;
|
||||
action.slot_name_define(slot, internal_name);
|
||||
const std::string internal_name = slot.identifier_prefix_for_idtype() + name_ref;
|
||||
action.slot_identifier_define(slot, internal_name);
|
||||
}
|
||||
|
||||
static void rna_ActionSlot_name_set(PointerRNA *ptr, const char *name)
|
||||
static void rna_ActionSlot_identifier_set(PointerRNA *ptr, const char *identifier)
|
||||
{
|
||||
animrig::Action &action = rna_action(ptr);
|
||||
animrig::Slot &slot = rna_data_slot(ptr);
|
||||
const StringRef name_ref(name);
|
||||
const StringRef identifier_ref(identifier);
|
||||
|
||||
if (name_ref.size() < animrig::Slot::name_length_min) {
|
||||
WM_report(RPT_ERROR, "Action slot names should be at least three characters");
|
||||
if (identifier_ref.size() < animrig::Slot::identifier_length_min) {
|
||||
WM_report(RPT_ERROR, "Action slot identifiers should be at least three characters");
|
||||
return;
|
||||
}
|
||||
|
||||
if (slot.has_idtype()) {
|
||||
/* Check if the new name is going to be compatible with the already-established ID type. */
|
||||
const std::string expect_prefix = slot.name_prefix_for_idtype();
|
||||
/* Check if the new identifier is going to be compatible with the already-established ID type.
|
||||
*/
|
||||
const std::string expect_prefix = slot.identifier_prefix_for_idtype();
|
||||
|
||||
if (!name_ref.startswith(expect_prefix)) {
|
||||
const std::string new_prefix = name_ref.substr(0, 2);
|
||||
if (!identifier_ref.startswith(expect_prefix)) {
|
||||
const std::string new_prefix = identifier_ref.substr(0, 2);
|
||||
WM_reportf(RPT_WARNING,
|
||||
"Action slot renamed to unexpected prefix \"%s\" (expected \"%s\").\n",
|
||||
"Action slot identifier set with unexpected prefix \"%s\" (expected \"%s\").\n",
|
||||
new_prefix.c_str(),
|
||||
expect_prefix.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
action.slot_name_define(slot, name);
|
||||
action.slot_identifier_define(slot, identifier);
|
||||
}
|
||||
|
||||
static void rna_ActionSlot_name_update(Main *bmain, Scene *, PointerRNA *ptr)
|
||||
static void rna_ActionSlot_identifier_update(Main *bmain, Scene *, PointerRNA *ptr)
|
||||
{
|
||||
animrig::Action &action = rna_action(ptr);
|
||||
animrig::Slot &slot = rna_data_slot(ptr);
|
||||
action.slot_name_propagate(*bmain, slot);
|
||||
action.slot_identifier_propagate(*bmain, slot);
|
||||
}
|
||||
|
||||
# ifndef NDEBUG
|
||||
@@ -378,7 +379,7 @@ static void rna_ActionSlot_debug_log_users(const ID *action_id, ActionSlot *dna_
|
||||
Slot &slot = dna_slot->wrap();
|
||||
|
||||
printf("\033[38;5;214mAction Slot users of '%s' on Action '%s':\033[0m\n",
|
||||
slot.name,
|
||||
slot.identifier,
|
||||
action.id.name + 2);
|
||||
if (bmain->is_action_slot_to_id_map_dirty) {
|
||||
printf(" User map is \033[93mdirty\033[0m, this will trigger a recompute.\n");
|
||||
@@ -1976,14 +1977,14 @@ static void rna_def_action_slot(BlenderRNA *brna)
|
||||
|
||||
RNA_define_lib_overridable(false);
|
||||
|
||||
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
|
||||
prop = RNA_def_property(srna, "identifier", PROP_STRING, PROP_NONE);
|
||||
RNA_def_struct_name_property(srna, prop);
|
||||
RNA_def_property_string_funcs(prop, nullptr, nullptr, "rna_ActionSlot_name_set");
|
||||
RNA_def_property_string_maxlength(prop, sizeof(ActionSlot::name) - 2);
|
||||
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN, "rna_ActionSlot_name_update");
|
||||
RNA_def_property_string_funcs(prop, nullptr, nullptr, "rna_ActionSlot_identifier_set");
|
||||
RNA_def_property_string_maxlength(prop, sizeof(ActionSlot::identifier) - 2);
|
||||
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN, "rna_ActionSlot_identifier_update");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Slot Name",
|
||||
"Slot Identifier",
|
||||
"Used when connecting an Action to a data-block, to find the correct slot handle. This is "
|
||||
"the display name, prefixed by two characters determined by the slot's ID type");
|
||||
|
||||
@@ -2006,8 +2007,8 @@ static void rna_def_action_slot(BlenderRNA *brna)
|
||||
"rna_ActionSlot_name_display_get",
|
||||
"rna_ActionSlot_name_display_length",
|
||||
"rna_ActionSlot_name_display_set");
|
||||
RNA_def_property_string_maxlength(prop, sizeof(ActionSlot::name) - 2);
|
||||
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN, "rna_ActionSlot_name_update");
|
||||
RNA_def_property_string_maxlength(prop, sizeof(ActionSlot::identifier) - 2);
|
||||
RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN, "rna_ActionSlot_identifier_update");
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Slot Display Name",
|
||||
|
||||
@@ -314,14 +314,16 @@ void rna_generic_action_slot_set(PointerRNA rna_slot_to_assign,
|
||||
case ActionSlotAssignmentResult::OK:
|
||||
break;
|
||||
case ActionSlotAssignmentResult::SlotNotFromAction:
|
||||
BKE_reportf(
|
||||
reports, RPT_ERROR, "This slot (%s) does not belong to the assigned Action", slot->name);
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"This slot (%s) does not belong to the assigned Action",
|
||||
slot->identifier);
|
||||
break;
|
||||
case ActionSlotAssignmentResult::SlotNotSuitable:
|
||||
BKE_reportf(reports,
|
||||
RPT_ERROR,
|
||||
"This slot (%s) is not suitable for this data-block type (%c%c)",
|
||||
slot->name,
|
||||
slot->identifier,
|
||||
animated_id.name[0],
|
||||
animated_id.name[1]);
|
||||
break;
|
||||
|
||||
@@ -64,9 +64,9 @@ class ActionSlotAssignmentTest(unittest.TestCase):
|
||||
camera_adt.action = action
|
||||
self.assertEqual(camera_adt.action_slot_handle, slot_camera.handle)
|
||||
|
||||
# Unassigning should keep the slot name.
|
||||
# Unassigning should keep the slot identifier.
|
||||
cube_adt.action = None
|
||||
self.assertEqual(cube_adt.action_slot_name, slot_cube.name)
|
||||
self.assertEqual(cube_adt.action_slot_name, slot_cube.identifier)
|
||||
|
||||
# It should not be possible to set the slot handle while the Action is unassigned.
|
||||
slot_extra = action.slots.new()
|
||||
@@ -248,7 +248,7 @@ class ChannelBagsTest(unittest.TestCase):
|
||||
self.action = bpy.data.actions.new('TestAction')
|
||||
|
||||
self.slot = self.action.slots.new()
|
||||
self.slot.name = 'OBTest'
|
||||
self.slot.identifier = 'OBTest'
|
||||
|
||||
self.layer = self.action.layers.new(name="Layer")
|
||||
self.strip = self.layer.strips.new(type='KEYFRAME')
|
||||
@@ -379,7 +379,7 @@ class DataPathTest(unittest.TestCase):
|
||||
action = bpy.data.actions.new('TestAction')
|
||||
|
||||
slot = action.slots.new()
|
||||
slot.name = 'OBTest'
|
||||
slot.identifier = 'OBTest'
|
||||
self.assertEqual("bpy.data.actions['TestAction'].slots[\"OBTest\"]", repr(slot))
|
||||
|
||||
layer = action.layers.new(name="Layer")
|
||||
@@ -436,7 +436,7 @@ class VersioningTest(unittest.TestCase):
|
||||
self.assertEqual(len(strip.channelbags[0].groups[0].channels), 9)
|
||||
|
||||
# Multi user slots do not get named after their users.
|
||||
self.assertEqual(action.slots[0].name, "OBSlot")
|
||||
self.assertEqual(action.slots[0].identifier, "OBSlot")
|
||||
|
||||
def test_action_constraint(self):
|
||||
constrained_object = bpy.data.objects["action_constraint_constrained"]
|
||||
@@ -469,7 +469,7 @@ class VersioningTest(unittest.TestCase):
|
||||
self.assertEqual(len(strip.channelbags[0].groups[1].channels), 10)
|
||||
|
||||
# Slots with a single user are named after their user.
|
||||
self.assertEqual(action.slots[0].name, "OBarmature_object")
|
||||
self.assertEqual(action.slots[0].identifier, "OBarmature_object")
|
||||
|
||||
for fcurve in strip.channelbags[0].groups[0].channels:
|
||||
self.assertEqual(fcurve.group.name, "Bone")
|
||||
|
||||
@@ -145,6 +145,10 @@ def check_constraints(self, input_arm, expected_arm, bone, exp_bone):
|
||||
msg = "Mismatching constraint value in pose.bones[%s].constraints[%s].%s" % (
|
||||
bone.name, const_name, var)
|
||||
self.assertEqual(value, exp_value, msg=msg)
|
||||
elif isinstance(value, bpy.types.ActionSlot):
|
||||
msg = "Mismatching constraint ActionSlot in pose.bones[%s].constraints[%s].%s" % (
|
||||
bone.name, const_name, var)
|
||||
self.assertEqual(value, exp_value, msg=msg)
|
||||
elif value is None:
|
||||
# Since above the types were compared already, if value is none, so is exp_value.
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user