|
|
|
|
@@ -207,15 +207,7 @@ void ARMATURE_OT_collection_move(wmOperatorType *ot)
|
|
|
|
|
"Direction to move the active Bone Collection towards");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef enum eMayCreate {
|
|
|
|
|
FAIL_IF_MISSING = 0,
|
|
|
|
|
CREATE_IF_MISSING = 1,
|
|
|
|
|
} eMayCreate;
|
|
|
|
|
|
|
|
|
|
static BoneCollection *get_bonecoll_named_or_active(bContext * /*C*/,
|
|
|
|
|
wmOperator *op,
|
|
|
|
|
Object *ob,
|
|
|
|
|
const eMayCreate may_create)
|
|
|
|
|
static BoneCollection *get_bonecoll_named_or_active(bContext * /*C*/, wmOperator *op, Object *ob)
|
|
|
|
|
{
|
|
|
|
|
bArmature *armature = static_cast<bArmature *>(ob->data);
|
|
|
|
|
|
|
|
|
|
@@ -227,21 +219,12 @@ static BoneCollection *get_bonecoll_named_or_active(bContext * /*C*/,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BoneCollection *bcoll = ANIM_armature_bonecoll_get_by_name(armature, bcoll_name);
|
|
|
|
|
if (bcoll) {
|
|
|
|
|
return bcoll;
|
|
|
|
|
if (!bcoll) {
|
|
|
|
|
WM_reportf(RPT_ERROR, "No bone collection named '%s'", bcoll_name);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (may_create) {
|
|
|
|
|
case CREATE_IF_MISSING:
|
|
|
|
|
bcoll = ANIM_armature_bonecoll_new(armature, bcoll_name);
|
|
|
|
|
ANIM_armature_bonecoll_active_set(armature, bcoll);
|
|
|
|
|
return bcoll;
|
|
|
|
|
case FAIL_IF_MISSING:
|
|
|
|
|
WM_reportf(RPT_ERROR, "No bone collection named '%s'", bcoll_name);
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
return bcoll;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using assign_bone_func = bool (*)(BoneCollection *bcoll, Bone *bone);
|
|
|
|
|
@@ -417,10 +400,7 @@ static int bone_collection_assign_exec(bContext *C, wmOperator *op)
|
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* NOTE: this operator can be called through the M/Shift+M shortcuts, which
|
|
|
|
|
* allow assigning to a newly-created bone collection. */
|
|
|
|
|
BoneCollection *bcoll = get_bonecoll_named_or_active(C, op, ob, CREATE_IF_MISSING);
|
|
|
|
|
BLI_assert_msg(bcoll, "Bone Collection should always be created");
|
|
|
|
|
BoneCollection *bcoll = get_bonecoll_named_or_active(C, op, ob);
|
|
|
|
|
if (bcoll == nullptr) {
|
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
}
|
|
|
|
|
@@ -485,6 +465,96 @@ void ARMATURE_OT_collection_assign(wmOperatorType *ot)
|
|
|
|
|
"active bone collection");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool bone_collection_create_and_assign_poll(bContext *C)
|
|
|
|
|
{
|
|
|
|
|
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 (ID_IS_LINKED(armature) && !ID_IS_OVERRIDE_LIBRARY(armature)) {
|
|
|
|
|
CTX_wm_operator_poll_msg_set(
|
|
|
|
|
C, "Cannot edit bone collections on linked Armatures without override");
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Assign selected pchans to the bone collection that the user selects */
|
|
|
|
|
static int bone_collection_create_and_assign_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
Object *ob = ED_object_context(C);
|
|
|
|
|
if (ob == nullptr) {
|
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bArmature *armature = static_cast<bArmature *>(ob->data);
|
|
|
|
|
|
|
|
|
|
char bcoll_name[MAX_NAME];
|
|
|
|
|
RNA_string_get(op->ptr, "name", bcoll_name);
|
|
|
|
|
|
|
|
|
|
/* Note that this bone collection can be removed later on, if the assignment part of this
|
|
|
|
|
* operation failed. */
|
|
|
|
|
BoneCollection *bcoll = ANIM_armature_bonecoll_new(armature, bcoll_name);
|
|
|
|
|
|
|
|
|
|
bool made_any_changes = false;
|
|
|
|
|
bool had_bones_to_assign = false;
|
|
|
|
|
const bool mode_is_supported = bone_collection_assign_mode_specific(
|
|
|
|
|
C,
|
|
|
|
|
ob,
|
|
|
|
|
bcoll,
|
|
|
|
|
ANIM_armature_bonecoll_assign,
|
|
|
|
|
ANIM_armature_bonecoll_assign_editbone,
|
|
|
|
|
&made_any_changes,
|
|
|
|
|
&had_bones_to_assign);
|
|
|
|
|
|
|
|
|
|
if (!mode_is_supported) {
|
|
|
|
|
WM_report(RPT_ERROR, "This operator only works in pose mode and armature edit mode");
|
|
|
|
|
ANIM_armature_bonecoll_remove(armature, bcoll);
|
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
}
|
|
|
|
|
if (!had_bones_to_assign) {
|
|
|
|
|
WM_report(RPT_WARNING, "No bones selected, nothing to assign to bone collection");
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
/* Not checking for `made_any_changes`, as if there were any bones to assign, they never could
|
|
|
|
|
* have already been assigned to this brand new bone collection. */
|
|
|
|
|
|
|
|
|
|
ANIM_armature_bonecoll_active_set(armature, bcoll);
|
|
|
|
|
WM_main_add_notifier(NC_OBJECT | ND_BONE_COLLECTION, &ob->id);
|
|
|
|
|
return OPERATOR_FINISHED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void ARMATURE_OT_collection_create_and_assign(wmOperatorType *ot)
|
|
|
|
|
{
|
|
|
|
|
/* identifiers */
|
|
|
|
|
ot->name = "Add Selected Bones to New Collection";
|
|
|
|
|
ot->idname = "ARMATURE_OT_collection_create_and_assign";
|
|
|
|
|
ot->description = "Create a new bone collection and assign all selected bones";
|
|
|
|
|
|
|
|
|
|
/* api callbacks */
|
|
|
|
|
ot->exec = bone_collection_create_and_assign_exec;
|
|
|
|
|
ot->poll = bone_collection_create_and_assign_poll;
|
|
|
|
|
|
|
|
|
|
/* flags */
|
|
|
|
|
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
|
|
|
|
|
|
|
|
|
/* properties */
|
|
|
|
|
RNA_def_string(ot->srna,
|
|
|
|
|
"name",
|
|
|
|
|
nullptr,
|
|
|
|
|
MAX_NAME,
|
|
|
|
|
"Bone Collection",
|
|
|
|
|
"Name of the bone collection to create");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int bone_collection_unassign_exec(bContext *C, wmOperator *op)
|
|
|
|
|
{
|
|
|
|
|
Object *ob = ED_object_context(C);
|
|
|
|
|
@@ -492,7 +562,7 @@ static int bone_collection_unassign_exec(bContext *C, wmOperator *op)
|
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BoneCollection *bcoll = get_bonecoll_named_or_active(C, op, ob, FAIL_IF_MISSING);
|
|
|
|
|
BoneCollection *bcoll = get_bonecoll_named_or_active(C, op, ob);
|
|
|
|
|
if (bcoll == nullptr) {
|
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
}
|
|
|
|
|
@@ -553,7 +623,7 @@ static int bone_collection_unassign_named_exec(bContext *C, wmOperator *op)
|
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
BoneCollection *bcoll = get_bonecoll_named_or_active(C, op, ob, FAIL_IF_MISSING);
|
|
|
|
|
BoneCollection *bcoll = get_bonecoll_named_or_active(C, op, ob);
|
|
|
|
|
if (bcoll == nullptr) {
|
|
|
|
|
return OPERATOR_CANCELLED;
|
|
|
|
|
}
|
|
|
|
|
|