Fix T41228: Selection of bones bug.

Turns out to be mostly some cleanup in Pose select code, got rid of magic numbers
(now understand usual SEL_xxx enums) in ED_pose_deselectall(), which was renamed
to ED_pose_de_selectall, and have a new bool parameter to ignore visibility status
in its process (was the root of the reported issue).

Also factorized slightly "(de)select all" code. Yet this area could use much more
cleanup probably...
This commit is contained in:
Bastien Montagne 2014-07-29 15:02:28 +02:00
parent e0fd1bf432
commit 976526559d
Notes: blender-bot 2023-04-04 07:45:26 +02:00
Referenced by issue #41228, Selection of bones bug.
3 changed files with 39 additions and 46 deletions

View File

@ -2802,7 +2802,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
/* deselect all other channels */
ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
if (pchan) ED_pose_deselectall(ob, 0);
if (pchan) ED_pose_de_selectall(ob, SEL_DESELECT, false);
/* only select channels in group and group itself */
for (fcu = agrp->channels.first; fcu && fcu->grp == agrp; fcu = fcu->next)
@ -2812,7 +2812,7 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index,
else {
/* select group by itself */
ANIM_deselect_anim_channels(ac, ac->data, ac->datatype, false, ACHANNEL_SETFLAG_CLEAR);
if (pchan) ED_pose_deselectall(ob, 0);
if (pchan) ED_pose_de_selectall(ob, SEL_DESELECT, false);
agrp->flag |= AGRP_SELECTED;
}

View File

@ -69,6 +69,28 @@
/* ***************** Pose Select Utilities ********************* */
/* Note: SEL_TOGGLE is assumed to have already been handled! */
static void pose_do_bone_select(bPoseChannel *pchan, const int select_mode) {
/* select pchan only if selectable, but deselect works always */
switch (select_mode) {
case SEL_SELECT:
if (!(pchan->bone->flag & BONE_UNSELECTABLE))
pchan->bone->flag |= BONE_SELECTED;
break;
case SEL_DESELECT:
pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
break;
case SEL_INVERT:
if (pchan->bone->flag & BONE_SELECTED) {
pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
else if (!(pchan->bone->flag & BONE_UNSELECTABLE)) {
pchan->bone->flag |= BONE_SELECTED;
}
break;
}
}
/* Utility method for changing the selection status of a bone */
void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select)
{
@ -139,7 +161,7 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor
}
if (!extend && !deselect && !toggle) {
ED_pose_deselectall(ob, 0);
ED_pose_de_selectall(ob, SEL_DESELECT, true);
nearBone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
arm->act_bone = nearBone;
}
@ -191,16 +213,12 @@ int ED_do_pose_selectbuffer(Scene *scene, Base *base, unsigned int *buffer, shor
return nearBone != NULL;
}
/* test==0: deselect all
* test==1: swap select (apply to all the opposite of current situation)
* test==2: only clear active tag
* test==3: swap select (no test / inverse selection status of all independently)
*/
void ED_pose_deselectall(Object *ob, int test)
/* 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT.
* When true, 'ignore_visibility' makes this func also affect invisible bones (hidden or on hidden layers). */
void ED_pose_de_selectall(Object *ob, int select_mode, const bool ignore_visibility)
{
bArmature *arm = ob->data;
bPoseChannel *pchan;
int selectmode = 0;
/* we call this from outliner too */
if (ob->pose == NULL) {
@ -208,31 +226,23 @@ void ED_pose_deselectall(Object *ob, int test)
}
/* Determine if we're selecting or deselecting */
if (test == 1) {
if (select_mode == SEL_TOGGLE) {
select_mode = SEL_SELECT;
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
if (PBONE_VISIBLE(arm, pchan->bone)) {
if (pchan->bone->flag & BONE_SELECTED)
if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
if (pchan->bone->flag & BONE_SELECTED) {
select_mode = SEL_DESELECT;
break;
}
}
}
if (pchan == NULL)
selectmode = 1;
}
else if (test == 2)
selectmode = 2;
/* Set the flags accordingly */
/* Set the flags accordingly */
for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
/* ignore the pchan if it isn't visible or if its selection cannot be changed */
if ((pchan->bone->layer & arm->layer) && !(pchan->bone->flag & (BONE_HIDDEN_P | BONE_UNSELECTABLE))) {
if (test == 3) {
pchan->bone->flag ^= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
else {
if (selectmode == 0) pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
else if (selectmode == 1) pchan->bone->flag |= BONE_SELECTED;
}
if (ignore_visibility || PBONE_VISIBLE(arm, pchan->bone)) {
pose_do_bone_select(pchan, select_mode);
}
}
}
@ -353,24 +363,7 @@ static int pose_de_select_all_exec(bContext *C, wmOperator *op)
/* Set the flags */
CTX_DATA_BEGIN(C, bPoseChannel *, pchan, visible_pose_bones)
{
/* select pchan only if selectable, but deselect works always */
switch (action) {
case SEL_SELECT:
if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)
pchan->bone->flag |= BONE_SELECTED;
break;
case SEL_DESELECT:
pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
break;
case SEL_INVERT:
if (pchan->bone->flag & BONE_SELECTED) {
pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
}
else if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) {
pchan->bone->flag |= BONE_SELECTED;
}
break;
}
pose_do_bone_select(pchan, action);
}
CTX_DATA_END;

View File

@ -174,7 +174,7 @@ void ED_armature_ebone_selectflag_disable(EditBone *ebone, int flag);
/* poseobject.c */
void ED_armature_exit_posemode(struct bContext *C, struct Base *base);
void ED_armature_enter_posemode(struct bContext *C, struct Base *base);
void ED_pose_deselectall(struct Object *ob, int test);
void ED_pose_de_selectall(struct Object *ob, int select_mode, const bool ignore_visibility);
void ED_pose_bone_select(struct Object *ob, struct bPoseChannel *pchan, bool select);
void ED_pose_recalculate_paths(struct Scene *scene, struct Object *ob);
struct Object *ED_pose_object_from_context(struct bContext *C);