Armature select-hierarchy now uses connected bones
Traverse down connected child bones (when available) Also remove redundant bone loops.
This commit is contained in:
parent
3e9947c4d4
commit
881e05fc54
|
@ -962,75 +962,78 @@ void ARMATURE_OT_select_similar(wmOperatorType *ot)
|
|||
|
||||
/* ********************* select hierarchy operator ************** */
|
||||
|
||||
/* Get the first available child of an editbone */
|
||||
static EditBone *editbone_get_child(bArmature *arm, EditBone *pabone, short use_visibility)
|
||||
{
|
||||
EditBone *curbone, *chbone = NULL;
|
||||
|
||||
for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
|
||||
if (curbone->parent == pabone) {
|
||||
if (use_visibility) {
|
||||
if ((arm->layer & curbone->layer) && !(pabone->flag & BONE_HIDDEN_A)) {
|
||||
chbone = curbone;
|
||||
}
|
||||
}
|
||||
else
|
||||
chbone = curbone;
|
||||
}
|
||||
}
|
||||
|
||||
return chbone;
|
||||
}
|
||||
|
||||
static int armature_select_hierarchy_exec(bContext *C, wmOperator *op)
|
||||
{
|
||||
Object *obedit = CTX_data_edit_object(C);
|
||||
Object *ob;
|
||||
bArmature *arm;
|
||||
EditBone *curbone, *pabone, *chbone;
|
||||
EditBone *ebone_active;
|
||||
int direction = RNA_enum_get(op->ptr, "direction");
|
||||
const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
|
||||
bool changed = false;
|
||||
|
||||
ob = obedit;
|
||||
arm = (bArmature *)ob->data;
|
||||
|
||||
for (curbone = arm->edbo->first; curbone; curbone = curbone->next) {
|
||||
/* only work on bone if it is visible and its selection can change */
|
||||
if (EBONE_SELECTABLE(arm, curbone)) {
|
||||
if (curbone == arm->act_edbone) {
|
||||
if (direction == BONE_SELECT_PARENT) {
|
||||
if (curbone->parent == NULL) continue;
|
||||
else pabone = curbone->parent;
|
||||
|
||||
if (EBONE_VISIBLE(arm, pabone)) {
|
||||
pabone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
|
||||
arm->act_edbone = pabone;
|
||||
if (pabone->parent) pabone->parent->flag |= BONE_TIPSEL;
|
||||
|
||||
if (!add_to_sel) curbone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
ebone_active = arm->act_edbone;
|
||||
if (ebone_active == NULL) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (direction == BONE_SELECT_PARENT) {
|
||||
if (ebone_active->parent) {
|
||||
EditBone *ebone_parent;
|
||||
|
||||
ebone_parent = ebone_active->parent;
|
||||
|
||||
if (EBONE_SELECTABLE(arm, ebone_parent)) {
|
||||
arm->act_edbone = ebone_parent;
|
||||
|
||||
if (!add_to_sel) {
|
||||
ED_armature_ebone_select_set(ebone_active, false);
|
||||
}
|
||||
else { // BONE_SELECT_CHILD
|
||||
chbone = editbone_get_child(arm, curbone, 1);
|
||||
if (chbone == NULL) continue;
|
||||
|
||||
if (EBONE_SELECTABLE(arm, chbone)) {
|
||||
chbone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
|
||||
arm->act_edbone = chbone;
|
||||
|
||||
if (!add_to_sel) {
|
||||
curbone->flag &= ~(BONE_SELECTED | BONE_ROOTSEL);
|
||||
if (curbone->parent) curbone->parent->flag &= ~BONE_TIPSEL;
|
||||
ED_armature_ebone_select_set(ebone_parent, true);
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else { /* BONE_SELECT_CHILD */
|
||||
EditBone *ebone_iter, *ebone_child = NULL;
|
||||
int pass;
|
||||
|
||||
/* first pass, only connected bones (the logical direct child) */
|
||||
for (pass = 0; pass < 2 && (ebone_child == NULL); pass++) {
|
||||
for (ebone_iter = arm->edbo->first; ebone_iter; ebone_iter = ebone_iter->next) {
|
||||
/* possible we have multiple children, some invisible */
|
||||
if (EBONE_SELECTABLE(arm, ebone_iter)) {
|
||||
if (ebone_iter->parent == ebone_active) {
|
||||
if ((pass == 1) || (ebone_iter->flag & BONE_CONNECTED)) {
|
||||
ebone_child = ebone_iter;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (ebone_child) {
|
||||
arm->act_edbone = ebone_child;
|
||||
|
||||
if (!add_to_sel) {
|
||||
ED_armature_ebone_select_set(ebone_active, false);
|
||||
}
|
||||
ED_armature_ebone_select_set(ebone_child, true);
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed == false) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
ED_armature_sync_selection(arm->edbo);
|
||||
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
|
||||
|
|
|
@ -518,71 +518,67 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op)
|
|||
{
|
||||
Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
|
||||
bArmature *arm = ob->data;
|
||||
Bone *curbone, *pabone, *chbone;
|
||||
bPoseChannel *pchan_act;
|
||||
int direction = RNA_enum_get(op->ptr, "direction");
|
||||
const bool add_to_sel = RNA_boolean_get(op->ptr, "extend");
|
||||
bool found = false;
|
||||
bool changed = false;
|
||||
|
||||
CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
|
||||
{
|
||||
curbone = pchan->bone;
|
||||
|
||||
if ((curbone->flag & BONE_UNSELECTABLE) == 0) {
|
||||
if (curbone == arm->act_bone) {
|
||||
if (direction == BONE_SELECT_PARENT) {
|
||||
if (pchan->parent == NULL) continue;
|
||||
else pabone = pchan->parent->bone;
|
||||
|
||||
if (PBONE_SELECTABLE(arm, pabone)) {
|
||||
if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
|
||||
pabone->flag |= BONE_SELECTED;
|
||||
arm->act_bone = pabone;
|
||||
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
pchan_act = BKE_pose_channel_active(ob);
|
||||
if (pchan_act == NULL) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
if (direction == BONE_SELECT_PARENT) {
|
||||
if (pchan_act->parent) {
|
||||
Bone *bone_parent;
|
||||
bone_parent = pchan_act->parent->bone;
|
||||
|
||||
if (PBONE_SELECTABLE(arm, bone_parent)) {
|
||||
if (!add_to_sel) {
|
||||
pchan_act->bone->flag &= ~BONE_SELECTED;
|
||||
}
|
||||
else { /* direction == BONE_SELECT_CHILD */
|
||||
/* the child member is only assigned to connected bones, see [#30340] */
|
||||
#if 0
|
||||
if (pchan->child == NULL) continue;
|
||||
else chbone = pchan->child->bone;
|
||||
#else
|
||||
/* instead. find _any_ visible child bone, using the first one is a little arbitrary - campbell */
|
||||
chbone = pchan->child ? pchan->child->bone : NULL;
|
||||
if (chbone == NULL) {
|
||||
bPoseChannel *pchan_child;
|
||||
bone_parent->flag |= BONE_SELECTED;
|
||||
arm->act_bone = bone_parent;
|
||||
|
||||
for (pchan_child = ob->pose->chanbase.first; pchan_child; pchan_child = pchan_child->next) {
|
||||
/* possible we have multiple children, some invisible */
|
||||
if (PBONE_SELECTABLE(arm, pchan_child->bone)) {
|
||||
if (pchan_child->parent == pchan) {
|
||||
chbone = pchan_child->bone;
|
||||
break;
|
||||
}
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else { /* direction == BONE_SELECT_CHILD */
|
||||
bPoseChannel *pchan_iter;
|
||||
Bone *bone_child = NULL;
|
||||
int pass;
|
||||
|
||||
/* first pass, only connected bones (the logical direct child) */
|
||||
for (pass = 0; pass < 2 && (bone_child == NULL); pass++) {
|
||||
for (pchan_iter = ob->pose->chanbase.first; pchan_iter; pchan_iter = pchan_iter->next) {
|
||||
/* possible we have multiple children, some invisible */
|
||||
if (PBONE_SELECTABLE(arm, pchan_iter->bone)) {
|
||||
if (pchan_iter->parent == pchan_act) {
|
||||
if ((pass == 1) || (pchan_iter->bone->flag & BONE_CONNECTED)) {
|
||||
bone_child = pchan_iter->bone;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (chbone == NULL) continue;
|
||||
#endif
|
||||
|
||||
if (PBONE_SELECTABLE(arm, chbone)) {
|
||||
if (!add_to_sel) curbone->flag &= ~BONE_SELECTED;
|
||||
chbone->flag |= BONE_SELECTED;
|
||||
arm->act_bone = chbone;
|
||||
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CTX_DATA_END;
|
||||
|
||||
if (found == 0)
|
||||
if (bone_child) {
|
||||
arm->act_bone = bone_child;
|
||||
|
||||
if (!add_to_sel) {
|
||||
pchan_act->bone->flag &= ~BONE_SELECTED;
|
||||
}
|
||||
bone_child->flag |= BONE_SELECTED;
|
||||
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (changed == false) {
|
||||
return OPERATOR_CANCELLED;
|
||||
}
|
||||
|
||||
/* updates */
|
||||
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
|
||||
|
|
Loading…
Reference in New Issue