Anim: add support for renaming bone collections added by overrides

Add a flag `BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL` that's only set on
bone collections that have been overridden locally.
This commit is contained in:
Sybren A. Stüvel 2023-09-14 14:31:01 +02:00
parent 89aee9defb
commit 347ffd6262
9 changed files with 118 additions and 9 deletions

View File

@ -89,6 +89,16 @@ class DATA_UL_bone_collections(UIList):
layout.prop(bcoll, "name", text="", emboss=False,
icon='DOT' if has_active_bone else 'BLANK1')
if armature.override_library:
icon = 'LIBRARY_DATA_OVERRIDE' if bcoll.is_local_override else 'BLANK1'
layout.prop(
bcoll,
"is_local_override",
text="",
emboss=False,
icon=icon)
layout.prop(bcoll, "is_visible", text="", emboss=False,
icon='HIDE_OFF' if bcoll.is_visible else 'HIDE_ON')

View File

@ -108,6 +108,15 @@ void ANIM_armature_bonecoll_active_set(struct bArmature *armature, struct BoneCo
void ANIM_armature_bonecoll_active_index_set(struct bArmature *armature,
int bone_collection_index);
/**
* Determine whether the given bone collection is editable.
*
* Bone collections are editable when they are local, so either on a local Armature or added to a
* linked Armature via a library override in the local file.
*/
bool ANIM_armature_bonecoll_is_editable(const struct bArmature *armature,
const struct BoneCollection *bcoll);
/**
* Move the bone collection by \a step places up/down.
*

View File

@ -111,6 +111,12 @@ static void bonecoll_ensure_name_unique(bArmature *armature, BoneCollection *bco
BoneCollection *ANIM_armature_bonecoll_new(bArmature *armature, const char *name)
{
BoneCollection *bcoll = ANIM_bonecoll_new(name);
if (!ID_IS_LINKED(&armature->id) && ID_IS_OVERRIDE_LIBRARY(&armature->id)) {
/* Mark this bone collection as local override, so that certain operations can be allowed. */
bcoll->flags |= BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL;
}
bonecoll_ensure_name_unique(armature, bcoll);
BLI_addtail(&armature->collections, bcoll);
return bcoll;
@ -187,6 +193,18 @@ void ANIM_armature_bonecoll_active_index_set(bArmature *armature, const int bone
armature->runtime.active_collection = bcoll;
}
bool ANIM_armature_bonecoll_is_editable(const bArmature *armature, const BoneCollection *bcoll)
{
const bool is_override = ID_IS_OVERRIDE_LIBRARY(armature);
if (ID_IS_LINKED(armature) && !is_override) {
return false;
}
if (is_override && (bcoll->flags & BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL) == 0) {
return false;
}
return true;
}
bool ANIM_armature_bonecoll_move(bArmature *armature, BoneCollection *bcoll, const int step)
{
if (bcoll == nullptr) {

View File

@ -174,4 +174,38 @@ TEST_F(ANIM_armature_bone_collections, active_set_clear_by_index)
EXPECT_STREQ("", arm.active_collection_name);
}
TEST_F(ANIM_armature_bone_collections, bcoll_is_editable)
{
BoneCollection *bcoll1 = ANIM_armature_bonecoll_new(&arm, "Bones 1");
BoneCollection *bcoll2 = ANIM_armature_bonecoll_new(&arm, "Bones 2");
EXPECT_EQ(0, bcoll1->flags & BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL);
EXPECT_EQ(0, bcoll2->flags & BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL);
EXPECT_TRUE(ANIM_armature_bonecoll_is_editable(&arm, bcoll1))
<< "Expecting local armature to be editable";
/* Fake that the armature is linked from another blend file. */
Library fake_lib;
arm.id.lib = &fake_lib;
EXPECT_FALSE(ANIM_armature_bonecoll_is_editable(&arm, bcoll1))
<< "Expecting local armature to not be editable";
/* Fake that the armature is an override, but linked from another blend file. */
IDOverrideLibrary fake_override;
bArmature fake_reference;
fake_override.reference = &fake_reference.id;
arm.id.override_library = &fake_override;
EXPECT_FALSE(ANIM_armature_bonecoll_is_editable(&arm, bcoll1))
<< "Expecting linked armature override to not be editable";
/* Fake that the armature is a local override. */
arm.id.lib = nullptr;
bcoll2->flags |= BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL;
EXPECT_FALSE(ANIM_armature_bonecoll_is_editable(&arm, bcoll1))
<< "Expecting linked bone collection on local armature override to not be editable";
EXPECT_TRUE(ANIM_armature_bonecoll_is_editable(&arm, bcoll2))
<< "Expecting local bone collection on local armature override to be editable";
}
} // namespace blender::animrig::tests

View File

@ -350,10 +350,18 @@ static void armature_blend_read_data(BlendDataReader *reader, ID *id)
}
BLO_read_list(reader, &arm->collections);
/* Bone collections added via an override can be edited, but ones that already exist in another
* blend file (so on the linked Armature) should not be touched. */
const bool reset_bcoll_override_flag = ID_IS_LINKED(&arm->id);
LISTBASE_FOREACH (BoneCollection *, bcoll, &arm->collections) {
direct_link_bone_collection(reader, bcoll);
if (reset_bcoll_override_flag) {
/* The linked Armature may have overrides in the library file already, and
* those should *not* be editable here. */
bcoll->flags &= ~BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL;
}
}
BLO_read_data_address(reader, &arm->active_collection);
BLO_read_data_address(reader, &arm->act_bone);
arm->act_edbone = nullptr;

View File

@ -53,6 +53,7 @@ static bool bone_collection_poll(bContext *C)
return false;
}
/* TODO: double-check these two conditions, I'm not sure they are correct: */
if (ID_IS_OVERRIDE_LIBRARY(ob->data)) {
CTX_wm_operator_poll_msg_set(C, "Cannot edit bone collections for library overrides");
return false;
@ -87,22 +88,32 @@ static bool bone_collection_add_poll(bContext *C)
return true;
}
/** Allow edits of local bone collection only (full local or local override). */
static bool active_bone_collection_poll(bContext *C)
{
if (!bone_collection_poll(C)) {
return false;
}
Object *ob = ED_object_context(C);
if (ob == nullptr) {
return false;
}
if (ob->type != OB_ARMATURE) {
CTX_wm_operator_poll_msg_set(C, "Bone collections can only be edited on an Armature");
return false;
}
bArmature *armature = static_cast<bArmature *>(ob->data);
if (armature->runtime.active_collection == nullptr) {
BoneCollection *bcoll = armature->runtime.active_collection;
if (bcoll == nullptr) {
CTX_wm_operator_poll_msg_set(C, "Armature has no active bone collection, select one first");
return false;
}
if (!ANIM_armature_bonecoll_is_editable(armature, bcoll)) {
CTX_wm_operator_poll_msg_set(
C, "Cannot edit bone collections that are linked from another blend file");
return false;
}
return true;
}

View File

@ -424,8 +424,9 @@ typedef enum eBone_BBoneHandleFlag {
typedef enum eBoneCollection_Flag {
BONE_COLLECTION_VISIBLE = (1 << 0),
BONE_COLLECTION_SELECTABLE = (1 << 1), /* Intended to be implemented in the not-so-far future. */
BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL = (1 << 2), /* Added by a local library override. */
} eBoneCollection_Flag;
ENUM_OPERATORS(eBoneCollection_Flag, BONE_COLLECTION_SELECTABLE)
ENUM_OPERATORS(eBoneCollection_Flag, BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL)
#ifdef __cplusplus

View File

@ -157,6 +157,12 @@ bool RNA_property_overridable_get(PointerRNA *ptr, PropertyRNA *prop)
return true;
}
}
else if (RNA_struct_is_a(ptr->type, &RNA_BoneCollection)) {
BoneCollection *bcoll = static_cast<BoneCollection *>(ptr->data);
if (bcoll->flags & BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL) {
return true;
}
}
/* If this is a RNA-defined property (real or 'virtual' IDProp),
* we want to use RNA prop flag. */
return !(prop->flag_override & PROPOVERRIDE_NO_COMPARISON) &&

View File

@ -334,8 +334,13 @@ static bool rna_Armature_collections_override_apply(Main *bmain,
bArmature *arm_dst = (bArmature *)ptr_dst->owner_id;
BoneCollection *bcoll_anchor = static_cast<BoneCollection *>(ptr_item_dst->data);
BoneCollection *bcoll_src = static_cast<BoneCollection *>(ptr_item_src->data);
BoneCollection *bcoll = ANIM_armature_bonecoll_insert_copy_after(
arm_dst, bcoll_anchor, bcoll_src);
ANIM_armature_bonecoll_insert_copy_after(arm_dst, bcoll_anchor, bcoll_src);
if (!ID_IS_LINKED(&arm_dst->id)) {
/* Mark this bone collection as local override, so that certain operations can be allowed. */
bcoll->flags |= BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL;
}
RNA_property_update_main(bmain, nullptr, ptr_dst, prop_dst);
return true;
@ -2061,7 +2066,6 @@ static void rna_def_bonecollection(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Name", "Unique within the Armature");
RNA_def_struct_name_property(srna, prop);
RNA_def_property_string_funcs(prop, nullptr, nullptr, "rna_BoneCollection_name_set");
// RNA_def_property_update(prop, 0, "rna_Bone_update_renamed");
prop = RNA_def_property(srna, "is_visible", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "flags", BONE_COLLECTION_VISIBLE);
@ -2072,6 +2076,14 @@ static void rna_def_bonecollection(BlenderRNA *brna)
RNA_def_property_update(prop, NC_OBJECT | ND_POSE, nullptr);
RNA_def_property_clear_flag(prop, PROP_ANIMATABLE);
prop = RNA_def_property(srna, "is_local_override", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "flags", BONE_COLLECTION_OVERRIDE_LIBRARY_LOCAL);
RNA_def_property_ui_text(
prop,
"Is Local Override",
"This collection was added via a library override in the current blend file");
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
prop = RNA_def_property(srna, "bones", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "Bone");
RNA_def_property_collection_funcs(prop,