diff options
author | Campbell Barton <campbell@blender.org> | 2022-03-15 13:03:04 +0300 |
---|---|---|
committer | Campbell Barton <campbell@blender.org> | 2022-03-16 06:48:25 +0300 |
commit | 5e5285baf621a0c225cb5fc06fcec6ffed8302d7 (patch) | |
tree | fcdc655a6b063d32a7630b648e126c20ade295f2 /source/blender/editors/armature | |
parent | 9a763d24f2b50ad38d22cad0a23d7344afe5f1c7 (diff) |
View 3D: move picking arguments into a struct & minor refactor
- Add SelectPick_Params struct to make picking logic more
straightforward and easier to extend.
- Use `eSelectOp` instead of booleans (extend, deselect, toggle)
which were used to represent 4 states (which wasn't obvious).
- Handle deselect_all when pocking instead of view3d_select_exec,
de-duplicate de-selection which was already needed in when replacing
the selection in picking functions.
- Handle outliner update & notifiers in the picking functions
instead of view3d_select_exec.
- Fix particle select deselect_all option which did nothing.
Diffstat (limited to 'source/blender/editors/armature')
-rw-r--r-- | source/blender/editors/armature/armature_select.c | 223 | ||||
-rw-r--r-- | source/blender/editors/armature/pose_select.c | 166 |
2 files changed, 224 insertions, 165 deletions
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index d7240782840..d1a5c128c35 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -951,127 +951,174 @@ bool ED_armature_edit_select_pick_bone(bContext *C, Base *basact, EditBone *ebone, const int selmask, - const bool extend, - const bool deselect, - const bool toggle) + const struct SelectPick_Params *params) { - if (!ebone) { - return false; - } - ViewLayer *view_layer = CTX_data_view_layer(C); View3D *v3d = CTX_wm_view3d(C); + bool changed = false; + bool found = false; - BLI_assert(BKE_object_is_in_editmode(basact->object)); - bArmature *arm = basact->object->data; - - if (!EBONE_SELECTABLE(arm, ebone)) { - return false; + if (ebone) { + bArmature *arm = basact->object->data; + if (EBONE_SELECTABLE(arm, ebone)) { + found = true; + } } - if (!extend && !deselect && !toggle) { + if ((params->sel_op == SEL_OP_SET) && (found || params->deselect_all)) { + /* Deselect everything. */ uint bases_len = 0; Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( view_layer, v3d, &bases_len); ED_armature_edit_deselect_all_multi_ex(bases, bases_len); MEM_freeN(bases); + changed = true; } - /* By definition the non-root connected bones have no root point drawn, - * so a root selection needs to be delivered to the parent tip. */ + if (found) { + BLI_assert(BKE_object_is_in_editmode(basact->object)); + bArmature *arm = basact->object->data; - if (selmask & BONE_SELECTED) { - if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { - /* Bone is in a chain. */ - if (extend) { - /* Select this bone. */ - ebone->flag |= BONE_TIPSEL; - ebone->parent->flag |= BONE_TIPSEL; - } - else if (deselect) { - /* Deselect this bone. */ - ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED); - /* Only deselect parent tip if it is not selected. */ - if (!(ebone->parent->flag & BONE_SELECTED)) { - ebone->parent->flag &= ~BONE_TIPSEL; - } - } - else if (toggle) { - /* Toggle inverts this bone's selection. */ - if (ebone->flag & BONE_SELECTED) { - /* Deselect this bone. */ - ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED); - /* Only deselect parent tip if it is not selected. */ - if (!(ebone->parent->flag & BONE_SELECTED)) { - ebone->parent->flag &= ~BONE_TIPSEL; + /* By definition the non-root connected bones have no root point drawn, + * so a root selection needs to be delivered to the parent tip. */ + + if (selmask & BONE_SELECTED) { + if (ebone->parent && (ebone->flag & BONE_CONNECTED)) { + + /* Bone is in a chain. */ + switch (params->sel_op) { + case SEL_OP_ADD: { + /* Select this bone. */ + ebone->flag |= BONE_TIPSEL; + ebone->parent->flag |= BONE_TIPSEL; + break; + } + case SEL_OP_SUB: { + /* Deselect this bone. */ + ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED); + /* Only deselect parent tip if it is not selected. */ + if (!(ebone->parent->flag & BONE_SELECTED)) { + ebone->parent->flag &= ~BONE_TIPSEL; + } + break; + } + case SEL_OP_XOR: { + /* Toggle inverts this bone's selection. */ + if (ebone->flag & BONE_SELECTED) { + /* Deselect this bone. */ + ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED); + /* Only deselect parent tip if it is not selected. */ + if (!(ebone->parent->flag & BONE_SELECTED)) { + ebone->parent->flag &= ~BONE_TIPSEL; + } + } + else { + /* Select this bone. */ + ebone->flag |= BONE_TIPSEL; + ebone->parent->flag |= BONE_TIPSEL; + } + break; + } + case SEL_OP_SET: { + /* Select this bone. */ + ebone->flag |= BONE_TIPSEL; + ebone->parent->flag |= BONE_TIPSEL; + break; + } + case SEL_OP_AND: { + BLI_assert_unreachable(); /* Doesn't make sense for picking. */ + break; } - } - else { - /* Select this bone. */ - ebone->flag |= BONE_TIPSEL; - ebone->parent->flag |= BONE_TIPSEL; } } else { - /* Select this bone. */ - ebone->flag |= BONE_TIPSEL; - ebone->parent->flag |= BONE_TIPSEL; + switch (params->sel_op) { + case SEL_OP_ADD: { + ebone->flag |= (BONE_TIPSEL | BONE_ROOTSEL); + break; + } + case SEL_OP_SUB: { + ebone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL); + break; + } + case SEL_OP_XOR: { + /* Toggle inverts this bone's selection. */ + if (ebone->flag & BONE_SELECTED) { + ebone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL); + } + else { + ebone->flag |= (BONE_TIPSEL | BONE_ROOTSEL); + } + break; + } + case SEL_OP_SET: { + ebone->flag |= (BONE_TIPSEL | BONE_ROOTSEL); + break; + } + case SEL_OP_AND: { + BLI_assert_unreachable(); /* Doesn't make sense for picking. */ + break; + } + } } } else { - if (extend) { - ebone->flag |= (BONE_TIPSEL | BONE_ROOTSEL); - } - else if (deselect) { - ebone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL); - } - else if (toggle) { - /* Toggle inverts this bone's selection. */ - if (ebone->flag & BONE_SELECTED) { - ebone->flag &= ~(BONE_TIPSEL | BONE_ROOTSEL); + switch (params->sel_op) { + case SEL_OP_ADD: { + ebone->flag |= selmask; + break; } - else { - ebone->flag |= (BONE_TIPSEL | BONE_ROOTSEL); + case SEL_OP_SUB: { + ebone->flag &= ~selmask; + break; + } + case SEL_OP_XOR: { + if (ebone->flag & selmask) { + ebone->flag &= ~selmask; + } + else { + ebone->flag |= selmask; + } + break; + } + case SEL_OP_SET: { + ebone->flag |= selmask; + break; + } + case SEL_OP_AND: { + BLI_assert_unreachable(); /* Doesn't make sense for picking. */ + break; } - } - else { - ebone->flag |= (BONE_TIPSEL | BONE_ROOTSEL); } } - } - else { - if (extend) { - ebone->flag |= selmask; - } - else if (deselect) { - ebone->flag &= ~selmask; - } - else if (toggle && (ebone->flag & selmask)) { - ebone->flag &= ~selmask; - } - else { - ebone->flag |= selmask; + + ED_armature_edit_sync_selection(arm->edbo); + + /* Then now check for active status. */ + if (ED_armature_ebone_selectflag_get(ebone)) { + arm->act_edbone = ebone; } - } - ED_armature_edit_sync_selection(arm->edbo); + if (view_layer->basact != basact) { + ED_object_base_activate(C, basact); + } - /* Then now check for active status. */ - if (ED_armature_ebone_selectflag_get(ebone)) { - arm->act_edbone = ebone; + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object); + DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE); + changed = true; } - if (view_layer->basact != basact) { - ED_object_base_activate(C, basact); + if (changed) { + ED_outliner_select_sync_from_edit_bone_tag(C); } - WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, basact->object); - DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE); - return true; + return changed || found; } -bool ED_armature_edit_select_pick( - bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) +bool ED_armature_edit_select_pick(bContext *C, + const int mval[2], + const struct SelectPick_Params *params) + { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; @@ -1084,7 +1131,7 @@ bool ED_armature_edit_select_pick( vc.mval[1] = mval[1]; nearBone = get_nearest_editbonepoint(&vc, true, true, &basact, &selmask); - return ED_armature_edit_select_pick_bone(C, basact, nearBone, selmask, extend, deselect, toggle); + return ED_armature_edit_select_pick_bone(C, basact, nearBone, selmask, params); } /** \} */ diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 12238280b06..1cf56389580 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -121,104 +121,120 @@ void ED_pose_bone_select(Object *ob, bPoseChannel *pchan, bool select) } } -void ED_armature_pose_select_pick_bone(ViewLayer *view_layer, +bool ED_armature_pose_select_pick_bone(ViewLayer *view_layer, View3D *v3d, Object *ob, Bone *bone, - const bool extend, - const bool deselect, - const bool toggle) + const struct SelectPick_Params *params) { - if (!ob || !ob->pose) { - return; - } - - Object *ob_act = OBACT(view_layer); - BLI_assert(OBEDIT_FROM_VIEW_LAYER(view_layer) == NULL); - - /* If the bone cannot be affected, don't do anything. */ - if (bone == NULL || (bone->flag & BONE_UNSELECTABLE)) { - return; - } - bArmature *arm = ob->data; + bool found = false; + bool changed = false; - /* Since we do unified select, we don't shift+select a bone if the - * armature object was not active yet. - * NOTE(campbell): special exception for armature mode so we can do multi-select - * we could check for multi-select explicitly but think its fine to - * always give predictable behavior in weight paint mode. */ - if ((ob_act == NULL) || ((ob_act != ob) && (ob_act->mode & OB_MODE_ALL_WEIGHT_PAINT) == 0)) { - /* When we are entering into posemode via toggle-select, - * from another active object - always select the bone. */ - if (!extend && !deselect && toggle) { - /* Re-select the bone again later in this function. */ - bone->flag &= ~BONE_SELECTED; + if (ob || ob->pose) { + if (bone && ((bone->flag & BONE_UNSELECTABLE) == 0)) { + found = true; } } - if (!extend && !deselect && !toggle) { - { - /* Don't use 'BKE_object_pose_base_array_get_unique' - * because we may be selecting from object mode. */ - FOREACH_VISIBLE_BASE_BEGIN (view_layer, v3d, base_iter) { - Object *ob_iter = base_iter->object; - if ((ob_iter->type == OB_ARMATURE) && (ob_iter->mode & OB_MODE_POSE)) { - if (ED_pose_deselect_all(ob_iter, SEL_DESELECT, true)) { - ED_pose_bone_select_tag_update(ob_iter); - } + if ((params->sel_op == SEL_OP_SET) && (found || params->deselect_all)) { + /* Don't use 'BKE_object_pose_base_array_get_unique' + * because we may be selecting from object mode. */ + FOREACH_VISIBLE_BASE_BEGIN (view_layer, v3d, base_iter) { + Object *ob_iter = base_iter->object; + if ((ob_iter->type == OB_ARMATURE) && (ob_iter->mode & OB_MODE_POSE)) { + if (ED_pose_deselect_all(ob_iter, SEL_DESELECT, true)) { + ED_pose_bone_select_tag_update(ob_iter); } } - FOREACH_VISIBLE_BASE_END; } - bone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - arm->act_bone = bone; + FOREACH_VISIBLE_BASE_END; + changed = true; } - else { - if (extend) { - bone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - arm->act_bone = bone; - } - else if (deselect) { - bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + + if (found) { + Object *ob_act = OBACT(view_layer); + BLI_assert(OBEDIT_FROM_VIEW_LAYER(view_layer) == NULL); + + /* If the bone cannot be affected, don't do anything. */ + bArmature *arm = ob->data; + + /* Since we do unified select, we don't shift+select a bone if the + * armature object was not active yet. + * NOTE(campbell): special exception for armature mode so we can do multi-select + * we could check for multi-select explicitly but think its fine to + * always give predictable behavior in weight paint mode. */ + if ((ob_act == NULL) || ((ob_act != ob) && (ob_act->mode & OB_MODE_ALL_WEIGHT_PAINT) == 0)) { + /* When we are entering into posemode via toggle-select, + * from another active object - always select the bone. */ + if (params->sel_op == SEL_OP_SET) { + /* Re-select the bone again later in this function. */ + bone->flag &= ~BONE_SELECTED; + } } - else if (toggle) { - if (bone->flag & BONE_SELECTED) { - /* If not active, we make it active. */ - if (bone != arm->act_bone) { - arm->act_bone = bone; + + switch (params->sel_op) { + case SEL_OP_ADD: { + bone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + arm->act_bone = bone; + break; + } + case SEL_OP_SUB: { + bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + break; + } + case SEL_OP_XOR: { + if (bone->flag & BONE_SELECTED) { + /* If not active, we make it active. */ + if (bone != arm->act_bone) { + arm->act_bone = bone; + } + else { + bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + } } else { - bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + bone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + arm->act_bone = bone; } + break; } - else { + case SEL_OP_SET: { bone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); arm->act_bone = bone; + break; + } + case SEL_OP_AND: { + BLI_assert_unreachable(); /* Doesn't make sense for picking. */ + break; } } - } - if (ob_act) { - /* In weightpaint we select the associated vertex group too. */ - if (ob_act->mode & OB_MODE_ALL_WEIGHT_PAINT) { - if (bone == arm->act_bone) { - ED_vgroup_select_by_name(ob_act, bone->name); - DEG_id_tag_update(&ob_act->id, ID_RECALC_GEOMETRY); + if (ob_act) { + /* In weightpaint we select the associated vertex group too. */ + if (ob_act->mode & OB_MODE_ALL_WEIGHT_PAINT) { + if (bone == arm->act_bone) { + ED_vgroup_select_by_name(ob_act, bone->name); + DEG_id_tag_update(&ob_act->id, ID_RECALC_GEOMETRY); + } } - } - /* If there are some dependencies for visualizing armature state - * (e.g. Mask Modifier in 'Armature' mode), force update. - */ - else if (arm->flag & ARM_HAS_VIZ_DEPS) { - /* NOTE: ob not ob_act here is intentional - it's the source of the - * bones being selected [T37247] + /* If there are some dependencies for visualizing armature state + * (e.g. Mask Modifier in 'Armature' mode), force update. */ - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + else if (arm->flag & ARM_HAS_VIZ_DEPS) { + /* NOTE: ob not ob_act here is intentional - it's the source of the + * bones being selected [T37247] + */ + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + } + + /* Tag armature for copy-on-write update (since act_bone is in armature not object). */ + DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE); } - /* Tag armature for copy-on-write update (since act_bone is in armature not object). */ - DEG_id_tag_update(&arm->id, ID_RECALC_COPY_ON_WRITE); + changed = true; } + + return changed || found; } bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer, @@ -226,9 +242,7 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer, Base *base, const struct GPUSelectResult *buffer, const short hits, - bool extend, - bool deselect, - bool toggle, + const struct SelectPick_Params *params, bool do_nearest) { Object *ob = base->object; @@ -243,9 +257,7 @@ bool ED_armature_pose_select_pick_with_buffer(ViewLayer *view_layer, nearBone = ED_armature_pick_bone_from_selectbuffer( &base, 1, buffer, hits, 1, do_nearest, &base_dummy); - ED_armature_pose_select_pick_bone(view_layer, v3d, ob, nearBone, extend, deselect, toggle); - - return nearBone != NULL; + return ED_armature_pose_select_pick_bone(view_layer, v3d, ob, nearBone, params); } void ED_armature_pose_select_in_wpaint_mode(ViewLayer *view_layer, Base *base_select) |