Armature Make/Clear Parent: Grey out options that don't do anything

In armature edit mode, the Make/Clear Parent operators don't do anything
in various cases, but only one of these cases was previously indicated,
and it was indicated by hiding the option completely instead of graying
it out.

Clear Parent (Alt+P) problems fixed:
- "Clear Parent" option always showed up, even when none of the selected
  bones had a parent.
- "Disconnect Bone" option always showed up, even when use_connected on
  all selected bones was already false.

Make Parent (Ctrl+P) problems fixed:
- "Keep Offset" option didn't show up when all selected bones' parent
  was already the active bone. This was correct, and this patch tries to
  make all behaviours consistent with this.
- "Connected" option always showed up, even when all selected bones'
  parent was already the active bone, and they all had use_connect set
  to True.

With this patch all options show up all the time, but in cases where
they would do nothing, they will be grayed out.

Reviewed By: sybren

Differential Revision: https://developer.blender.org/D6100
This commit is contained in:
Demeter Dzadik 2021-11-09 11:54:20 +01:00 committed by Sybren A. Stüvel
parent 4e2478940e
commit de8e13036b
1 changed files with 77 additions and 16 deletions

View File

@ -745,6 +745,10 @@ void ARMATURE_OT_separate(wmOperatorType *ot)
#define ARM_PAR_CONNECT 1
#define ARM_PAR_OFFSET 2
/* armature un-parenting options */
#define ARM_PAR_CLEAR 1
#define ARM_PAR_CLEAR_DISCONNECT 2
/* check for null, before calling! */
static void bone_connect_to_existing_parent(EditBone *bone)
{
@ -904,19 +908,29 @@ static int armature_parent_set_invoke(bContext *C,
wmOperator *UNUSED(op),
const wmEvent *UNUSED(event))
{
bool all_childbones = false;
// False when all selected bones are parented to the active bone.
bool enable_offset = false;
// False when all selected bones are connected to the active bone.
bool enable_connect = false;
{
Object *ob = CTX_data_edit_object(C);
bArmature *arm = ob->data;
EditBone *actbone = arm->act_edbone;
LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (EBONE_EDITABLE(ebone) && (ebone->flag & BONE_SELECTED)) {
if (ebone != actbone) {
if (ebone->parent != actbone) {
all_childbones = true;
break;
}
}
if (!EBONE_EDITABLE(ebone) || !(ebone->flag & BONE_SELECTED)) {
continue;
}
if (ebone == actbone) {
continue;
}
if (ebone->parent != actbone) {
enable_offset = true;
enable_connect = true;
break;
}
else if (!(ebone->flag & BONE_CONNECTED)) {
enable_connect = true;
}
}
}
@ -924,11 +938,14 @@ static int armature_parent_set_invoke(bContext *C,
uiPopupMenu *pup = UI_popup_menu_begin(
C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Parent"), ICON_NONE);
uiLayout *layout = UI_popup_menu_layout(pup);
uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT);
if (all_childbones) {
/* Object becomes parent, make the associated menus. */
uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET);
}
uiLayout *row_offset = uiLayoutRow(layout, false);
uiLayoutSetEnabled(row_offset, enable_offset);
uiItemEnumO(row_offset, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET);
uiLayout *row_connect = uiLayoutRow(layout, false);
uiLayoutSetEnabled(row_connect, enable_connect);
uiItemEnumO(row_connect, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT);
UI_popup_menu_end(C, pup);
@ -955,8 +972,8 @@ void ARMATURE_OT_parent_set(wmOperatorType *ot)
}
static const EnumPropertyItem prop_editarm_clear_parent_types[] = {
{1, "CLEAR", 0, "Clear Parent", ""},
{2, "DISCONNECT", 0, "Disconnect Bone", ""},
{ARM_PAR_CLEAR, "CLEAR", 0, "Clear Parent", ""},
{ARM_PAR_CLEAR_DISCONNECT, "DISCONNECT", 0, "Disconnect Bone", ""},
{0, NULL, 0, NULL, NULL},
};
@ -1012,6 +1029,50 @@ static int armature_parent_clear_exec(bContext *C, wmOperator *op)
return OPERATOR_FINISHED;
}
static int armature_parent_clear_invoke(bContext *C,
wmOperator *UNUSED(op),
const wmEvent *UNUSED(event))
{
// False when no selected bones are connected to the active bone.
bool enable_disconnect = false;
// False when no selected bones are parented to the active bone.
bool enable_clear = false;
{
Object *ob = CTX_data_edit_object(C);
bArmature *arm = ob->data;
LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) {
if (!EBONE_EDITABLE(ebone) || !(ebone->flag & BONE_SELECTED)) {
continue;
}
if (ebone->parent == NULL) {
continue;
}
enable_clear = true;
if (ebone->flag & BONE_CONNECTED) {
enable_disconnect = true;
break;
}
}
}
uiPopupMenu *pup = UI_popup_menu_begin(
C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Parent"), ICON_NONE);
uiLayout *layout = UI_popup_menu_layout(pup);
uiLayout *row_clear = uiLayoutRow(layout, false);
uiLayoutSetEnabled(row_clear, enable_clear);
uiItemEnumO(row_clear, "ARMATURE_OT_parent_clear", NULL, 0, "type", ARM_PAR_CLEAR);
uiLayout *row_disconnect = uiLayoutRow(layout, false);
uiLayoutSetEnabled(row_disconnect, enable_disconnect);
uiItemEnumO(row_disconnect, "ARMATURE_OT_parent_clear", NULL, 0, "type", ARM_PAR_CLEAR_DISCONNECT);
UI_popup_menu_end(C, pup);
return OPERATOR_INTERFACE;
}
void ARMATURE_OT_parent_clear(wmOperatorType *ot)
{
/* identifiers */
@ -1021,7 +1082,7 @@ void ARMATURE_OT_parent_clear(wmOperatorType *ot)
"Remove the parent-child relationship between selected bones and their parents";
/* api callbacks */
ot->invoke = WM_menu_invoke;
ot->invoke = armature_parent_clear_invoke;
ot->exec = armature_parent_clear_exec;
ot->poll = ED_operator_editarmature;