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 | |
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')
20 files changed, 913 insertions, 657 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) diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 2dcddd01670..1c1783669c3 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -44,6 +44,7 @@ #include "ED_object.h" #include "ED_outliner.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_transform.h" #include "ED_transform_snap_object_context.h" #include "ED_types.h" @@ -4722,8 +4723,9 @@ void CURVE_OT_make_segment(wmOperatorType *ot) /** \name Pick Select from 3D View * \{ */ -bool ED_curve_editnurb_select_pick( - bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) +bool ED_curve_editnurb_select_pick(bContext *C, + const int mval[2], + const struct SelectPick_Params *params) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; @@ -4732,129 +4734,144 @@ bool ED_curve_editnurb_select_pick( BPoint *bp = NULL; Base *basact = NULL; short hand; + bool changed = false; view3d_operator_needs_opengl(C); ED_view3d_viewcontext_init(C, &vc, depsgraph); copy_v2_v2_int(vc.mval, mval); - if (ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, &hand, &basact)) { - Object *obedit = basact->object; - Curve *cu = obedit->data; - ListBase *editnurb = object_editcurve_get(obedit); - const void *vert = BKE_curve_vert_active_get(cu); + const bool found = ED_curve_pick_vert(&vc, 1, &nu, &bezt, &bp, &hand, &basact); - if (!extend && !deselect && !toggle) { - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( - vc.view_layer, vc.v3d, &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob_iter = objects[ob_index]; + if ((params->sel_op == SEL_OP_SET) && (found || params->deselect_all)) { + /* Deselect everything. */ + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + vc.view_layer, vc.v3d, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob_iter = objects[ob_index]; - ED_curve_deselect_all(((Curve *)ob_iter->data)->editnurb); + ED_curve_deselect_all(((Curve *)ob_iter->data)->editnurb); - DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT | ID_RECALC_COPY_ON_WRITE); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); - } - MEM_freeN(objects); + DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT | ID_RECALC_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); } + MEM_freeN(objects); + changed = true; + } - if (extend) { - if (bezt) { - if (hand == 1) { - select_beztriple(bezt, SELECT, SELECT, HIDDEN); - } - else { - if (hand == 0) { - bezt->f1 |= SELECT; + if (found) { + Object *obedit = basact->object; + Curve *cu = obedit->data; + ListBase *editnurb = object_editcurve_get(obedit); + const void *vert = BKE_curve_vert_active_get(cu); + + switch (params->sel_op) { + case SEL_OP_ADD: { + if (bezt) { + if (hand == 1) { + select_beztriple(bezt, SELECT, SELECT, HIDDEN); } else { - bezt->f3 |= SELECT; - } - } - BKE_curve_nurb_vert_active_set(cu, nu, bezt); - } - else { - select_bpoint(bp, SELECT, SELECT, HIDDEN); - BKE_curve_nurb_vert_active_set(cu, nu, bp); - } - } - else if (deselect) { - if (bezt) { - if (hand == 1) { - select_beztriple(bezt, DESELECT, SELECT, HIDDEN); - if (bezt == vert) { - cu->actvert = CU_ACT_NONE; + if (hand == 0) { + bezt->f1 |= SELECT; + } + else { + bezt->f3 |= SELECT; + } } - } - else if (hand == 0) { - bezt->f1 &= ~SELECT; + BKE_curve_nurb_vert_active_set(cu, nu, bezt); } else { - bezt->f3 &= ~SELECT; - } - } - else { - select_bpoint(bp, DESELECT, SELECT, HIDDEN); - if (bp == vert) { - cu->actvert = CU_ACT_NONE; + select_bpoint(bp, SELECT, SELECT, HIDDEN); + BKE_curve_nurb_vert_active_set(cu, nu, bp); } + break; } - } - else if (toggle) { - if (bezt) { - if (hand == 1) { - if (bezt->f2 & SELECT) { + case SEL_OP_SUB: { + if (bezt) { + if (hand == 1) { select_beztriple(bezt, DESELECT, SELECT, HIDDEN); if (bezt == vert) { cu->actvert = CU_ACT_NONE; } } + else if (hand == 0) { + bezt->f1 &= ~SELECT; + } else { - select_beztriple(bezt, SELECT, SELECT, HIDDEN); - BKE_curve_nurb_vert_active_set(cu, nu, bezt); + bezt->f3 &= ~SELECT; } } - else if (hand == 0) { - bezt->f1 ^= SELECT; - } else { - bezt->f3 ^= SELECT; - } - } - else { - if (bp->f1 & SELECT) { select_bpoint(bp, DESELECT, SELECT, HIDDEN); if (bp == vert) { cu->actvert = CU_ACT_NONE; } } + break; + } + case SEL_OP_XOR: { + if (bezt) { + if (hand == 1) { + if (bezt->f2 & SELECT) { + select_beztriple(bezt, DESELECT, SELECT, HIDDEN); + if (bezt == vert) { + cu->actvert = CU_ACT_NONE; + } + } + else { + select_beztriple(bezt, SELECT, SELECT, HIDDEN); + BKE_curve_nurb_vert_active_set(cu, nu, bezt); + } + } + else if (hand == 0) { + bezt->f1 ^= SELECT; + } + else { + bezt->f3 ^= SELECT; + } + } else { - select_bpoint(bp, SELECT, SELECT, HIDDEN); - BKE_curve_nurb_vert_active_set(cu, nu, bp); + if (bp->f1 & SELECT) { + select_bpoint(bp, DESELECT, SELECT, HIDDEN); + if (bp == vert) { + cu->actvert = CU_ACT_NONE; + } + } + else { + select_bpoint(bp, SELECT, SELECT, HIDDEN); + BKE_curve_nurb_vert_active_set(cu, nu, bp); + } } + break; } - } - else { - BKE_nurbList_flag_set(editnurb, SELECT, false); + case SEL_OP_SET: { + BKE_nurbList_flag_set(editnurb, SELECT, false); - if (bezt) { + if (bezt) { - if (hand == 1) { - select_beztriple(bezt, SELECT, SELECT, HIDDEN); - } - else { - if (hand == 0) { - bezt->f1 |= SELECT; + if (hand == 1) { + select_beztriple(bezt, SELECT, SELECT, HIDDEN); } else { - bezt->f3 |= SELECT; + if (hand == 0) { + bezt->f1 |= SELECT; + } + else { + bezt->f3 |= SELECT; + } } + BKE_curve_nurb_vert_active_set(cu, nu, bezt); + } + else { + select_bpoint(bp, SELECT, SELECT, HIDDEN); + BKE_curve_nurb_vert_active_set(cu, nu, bp); } - BKE_curve_nurb_vert_active_set(cu, nu, bezt); + break; } - else { - select_bpoint(bp, SELECT, SELECT, HIDDEN); - BKE_curve_nurb_vert_active_set(cu, nu, bp); + case SEL_OP_AND: { + BLI_assert_unreachable(); /* Doesn't make sense for picking. */ + break; } } @@ -4876,10 +4893,10 @@ bool ED_curve_editnurb_select_pick( DEG_id_tag_update(obedit->data, ID_RECALC_SELECT | ID_RECALC_COPY_ON_WRITE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); - return true; + changed = true; } - return false; + return changed || found; } /** \} */ diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index fdd145ff8cf..0afb1c2f4af 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -2184,7 +2184,10 @@ void FONT_OT_unlink(wmOperatorType *ot) } bool ED_curve_editfont_select_pick( - bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) + bContext *C, + const int mval[2], + /* NOTE: `params->deselect_all` is ignored as only one text-box is active at once. */ + const struct SelectPick_Params *params) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Object *obedit = CTX_data_edit_object(C); @@ -2203,9 +2206,7 @@ bool ED_curve_editfont_select_pick( ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); /* currently only select active */ - (void)extend; - (void)deselect; - (void)toggle; + (void)params; for (i_iter = 0; i_iter < cu->totbox; i_iter++) { int i = (i_iter + i_actbox) % cu->totbox; diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 2f5f82e332c..84efc875be7 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -27,6 +27,7 @@ struct MeshDeformModifierData; struct Object; struct ReportList; struct Scene; +struct SelectPick_Params; struct UndoType; struct View3D; struct ViewLayer; @@ -164,18 +165,20 @@ bool ED_armature_edit_deselect_all_visible(struct Object *obedit); bool ED_armature_edit_deselect_all_multi_ex(struct Base **bases, uint bases_len); bool ED_armature_edit_deselect_all_visible_multi_ex(struct Base **bases, uint bases_len); bool ED_armature_edit_deselect_all_visible_multi(struct bContext *C); +/** + * \return True when pick finds an element or the selection changed. + */ bool ED_armature_edit_select_pick_bone(struct bContext *C, struct Base *basact, struct EditBone *ebone, int selmask, - bool extend, - bool deselect, - bool toggle); + const struct SelectPick_Params *params); /** * Bone selection picking for armature edit-mode in the view3d. */ -bool ED_armature_edit_select_pick( - struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); +bool ED_armature_edit_select_pick(struct bContext *C, + const int mval[2], + const struct SelectPick_Params *params); /** * Perform a selection operation on elements which have been 'touched', * use for lasso & border select but can be used elsewhere too. @@ -305,25 +308,26 @@ void ED_pose_recalculate_paths(struct bContext *C, /* pose_select.c */ -void ED_armature_pose_select_pick_bone(struct ViewLayer *view_layer, +/** + * \return True when pick finds an element or the selection changed. + */ +bool ED_armature_pose_select_pick_bone(struct ViewLayer *view_layer, struct View3D *v3d, struct Object *ob, struct Bone *bone, - bool extend, - bool deselect, - bool toggle); + const struct SelectPick_Params *params); /** * Called for mode-less pose selection. * assumes the active object is still on old situation. + * + * \return True when pick finds an element or the selection changed. */ bool ED_armature_pose_select_pick_with_buffer(struct ViewLayer *view_layer, struct View3D *v3d, struct Base *base, const struct GPUSelectResult *buffer, short hits, - bool extend, - bool deselect, - bool toggle, + const struct SelectPick_Params *params, bool do_nearest); /** * While in weight-paint mode, a single pose may be active as well. diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h index c97f97a2ddc..6097e7c69d9 100644 --- a/source/blender/editors/include/ED_curve.h +++ b/source/blender/editors/include/ED_curve.h @@ -19,6 +19,7 @@ struct EditNurb; struct Main; struct Nurb; struct Object; +struct SelectPick_Params; struct Text; struct UndoType; struct View3D; @@ -46,8 +47,12 @@ void ED_curve_editnurb_load(struct Main *bmain, struct Object *obedit); void ED_curve_editnurb_make(struct Object *obedit); void ED_curve_editnurb_free(struct Object *obedit); -bool ED_curve_editnurb_select_pick( - struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); +/** + * \return True when pick finds an element or the selection changed. + */ +bool ED_curve_editnurb_select_pick(struct bContext *C, + const int mval[2], + const struct SelectPick_Params *params); struct Nurb *ED_curve_add_nurbs_primitive( struct bContext *C, struct Object *obedit, float mat[4][4], int type, int newob); @@ -100,10 +105,13 @@ int ED_curve_updateAnimPaths(struct Main *bmain, struct Curve *cu); bool ED_curve_active_center(struct Curve *cu, float center[3]); /** - * TextBox selection + * Text box selection. + * + * \return True when pick finds an element or the selection changed. */ -bool ED_curve_editfont_select_pick( - struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); +bool ED_curve_editfont_select_pick(struct bContext *C, + const int mval[2], + const struct SelectPick_Params *params); /* editfont_undo.c */ diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h index eddf69e1cb6..1b9311cbacf 100644 --- a/source/blender/editors/include/ED_lattice.h +++ b/source/blender/editors/include/ED_lattice.h @@ -13,6 +13,7 @@ extern "C" { struct Base; struct Object; +struct SelectPick_Params; struct UndoType; struct wmKeyConfig; @@ -24,8 +25,12 @@ void ED_keymap_lattice(struct wmKeyConfig *keyconf); /* editlattice_select.c */ bool ED_lattice_flags_set(struct Object *obedit, int flag); -bool ED_lattice_select_pick( - struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); +/** + * \return True when pick finds an element or the selection changed. + */ +bool ED_lattice_select_pick(struct bContext *C, + const int mval[2], + const struct SelectPick_Params *params); bool ED_lattice_deselect_all_multi_ex(struct Base **bases, uint bases_len); bool ED_lattice_deselect_all_multi(struct bContext *C); diff --git a/source/blender/editors/include/ED_mball.h b/source/blender/editors/include/ED_mball.h index e0c921ea0db..74071765716 100644 --- a/source/blender/editors/include/ED_mball.h +++ b/source/blender/editors/include/ED_mball.h @@ -13,6 +13,7 @@ extern "C" { struct Base; struct Object; +struct SelectPick_Params; struct UndoType; struct bContext; struct wmKeyConfig; @@ -32,10 +33,13 @@ struct MetaElem *ED_mball_add_primitive(struct bContext *C, int type); /** - * Select MetaElement with mouse click (user can select radius circle or stiffness circle). + * Select meta-element with mouse click (user can select radius circle or stiffness circle). + * + * \return True when pick finds an element or the selection changed. */ -bool ED_mball_select_pick( - struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); +bool ED_mball_select_pick(struct bContext *C, + const int mval[2], + const struct SelectPick_Params *params); bool ED_mball_deselect_all_multi_ex(struct Base **bases, uint bases_len); bool ED_mball_deselect_all_multi(struct bContext *C); diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 68e46dfa0e5..03ca4cd062b 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -31,6 +31,7 @@ struct Mesh; struct Object; struct ReportList; struct Scene; +struct SelectPick_Params; struct UndoType; struct UvMapVert; struct UvVertMap; @@ -268,8 +269,9 @@ bool EDBM_unified_findnearest_from_raycast(struct ViewContext *vc, struct BMEdge **r_eed, struct BMFace **r_efa); -bool EDBM_select_pick( - struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); +bool EDBM_select_pick(struct bContext *C, + const int mval[2], + const struct SelectPick_Params *params); /** * When switching select mode, makes sure selection is consistent for editing @@ -387,12 +389,13 @@ void ED_keymap_mesh(struct wmKeyConfig *keyconf); * use in object mode when selecting faces (while painting). */ void paintface_flush_flags(struct bContext *C, struct Object *ob, short flag); +/** + * \return True when pick finds an element or the selection changed. + */ bool paintface_mouse_select(struct bContext *C, - struct Object *ob, const int mval[2], - bool extend, - bool deselect, - bool toggle); + const struct SelectPick_Params *params, + struct Object *ob); bool paintface_deselect_all_visible(struct bContext *C, struct Object *ob, int action, diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h index a4797ff167c..553aa444891 100644 --- a/source/blender/editors/include/ED_particle.h +++ b/source/blender/editors/include/ED_particle.h @@ -16,6 +16,7 @@ struct PTCacheEdit; struct ParticleEditSettings; struct ParticleSystem; struct Scene; +struct SelectPick_Params; struct UndoType; struct ViewLayer; struct bContext; @@ -54,8 +55,9 @@ void PE_update_object(struct Depsgraph *depsgraph, /* selection tools */ -bool PE_mouse_particles( - struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); +bool PE_mouse_particles(struct bContext *C, + const int mval[2], + const struct SelectPick_Params *params); bool PE_box_select(struct bContext *C, const struct rcti *rect, int sel_op); bool PE_circle_select(struct bContext *C, struct wmGenericUserData *wm_userdata, diff --git a/source/blender/editors/include/ED_select_utils.h b/source/blender/editors/include/ED_select_utils.h index 26d8d0a3d8c..c24c9168fe8 100644 --- a/source/blender/editors/include/ED_select_utils.h +++ b/source/blender/editors/include/ED_select_utils.h @@ -70,6 +70,25 @@ bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree, */ eSelectOp ED_select_op_modal(eSelectOp sel_op, bool is_first); +/** Argument passed to picking functions. */ +struct SelectPick_Params { + /** + * - #SEL_OP_ADD named "extend" from operators. + * - #SEL_OP_SUB named "deselect" from operators. + * - #SEL_OP_XOR named "toggle" from operators. + * - #SEL_OP_AND (never used for picking). + * - #SEL_OP_SET use when "extend", "deselect" and "toggle" are all disabled. + */ + eSelectOp sel_op; + /** Deselect all, even when there is nothing found at the cursor location. */ + bool deselect_all; +}; + +/** + * Utility to get #eSelectPickMode from booleans for convenience. + */ +eSelectOp ED_select_op_from_booleans(bool extend, bool deselect, bool toggle); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/lattice/editlattice_select.c b/source/blender/editors/lattice/editlattice_select.c index d1635078126..883476aed7d 100644 --- a/source/blender/editors/lattice/editlattice_select.c +++ b/source/blender/editors/lattice/editlattice_select.c @@ -616,49 +616,63 @@ static BPoint *findnearestLattvert(ViewContext *vc, int sel, Base **r_base) return data.bp; } -bool ED_lattice_select_pick( - bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) +bool ED_lattice_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); ViewContext vc; BPoint *bp = NULL; Base *basact = NULL; + bool changed = false; ED_view3d_viewcontext_init(C, &vc, depsgraph); vc.mval[0] = mval[0]; vc.mval[1] = mval[1]; bp = findnearestLattvert(&vc, true, &basact); - if (bp) { - ED_view3d_viewcontext_init_object(&vc, basact->object); - Lattice *lt = ((Lattice *)vc.obedit->data)->editlatt->latt; + const bool found = (bp != NULL); - if (!extend && !deselect && !toggle) { - uint objects_len = 0; - Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( - vc.view_layer, vc.v3d, &objects_len); - for (uint ob_index = 0; ob_index < objects_len; ob_index++) { - Object *ob = objects[ob_index]; - if (ED_lattice_flags_set(ob, 0)) { - DEG_id_tag_update(ob->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); - } + if ((params->sel_op == SEL_OP_SET) && (found || params->deselect_all)) { + /* Deselect everything. */ + uint objects_len = 0; + Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( + vc.view_layer, vc.v3d, &objects_len); + for (uint ob_index = 0; ob_index < objects_len; ob_index++) { + Object *ob = objects[ob_index]; + if (ED_lattice_flags_set(ob, 0)) { + DEG_id_tag_update(ob->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); } - MEM_freeN(objects); } + MEM_freeN(objects); + changed = true; + } - if (extend) { - bp->f1 |= SELECT; - } - else if (deselect) { - bp->f1 &= ~SELECT; - } - else if (toggle) { - bp->f1 ^= SELECT; /* swap */ - } - else { - ED_lattice_flags_set(vc.obedit, 0); - bp->f1 |= SELECT; + if (found) { + ED_view3d_viewcontext_init_object(&vc, basact->object); + Lattice *lt = ((Lattice *)vc.obedit->data)->editlatt->latt; + + switch (params->sel_op) { + case SEL_OP_ADD: { + bp->f1 |= SELECT; + break; + } + case SEL_OP_SUB: { + bp->f1 &= ~SELECT; + break; + } + case SEL_OP_XOR: { + bp->f1 ^= SELECT; /* swap */ + break; + } + case SEL_OP_SET: { + ED_lattice_flags_set(vc.obedit, 0); + bp->f1 |= SELECT; + break; + } + case SEL_OP_AND: { + BLI_assert_unreachable(); /* Doesn't make sense for picking. */ + break; + } } if (bp->f1 & SELECT) { @@ -675,10 +689,10 @@ bool ED_lattice_select_pick( DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); - return true; + changed = true; } - return false; + return changed || found; } /** \} */ diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 8a1e12c76c5..9832f7ba9cf 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -366,59 +366,71 @@ bool paintface_minmax(Object *ob, float r_min[3], float r_max[3]) return ok; } -bool paintface_mouse_select( - struct bContext *C, Object *ob, const int mval[2], bool extend, bool deselect, bool toggle) +bool paintface_mouse_select(struct bContext *C, + const int mval[2], + const struct SelectPick_Params *params, + Object *ob) { Mesh *me; - MPoly *mpoly_sel; + MPoly *mpoly_sel = NULL; uint index; + bool changed = false; + bool found = false; /* Get the face under the cursor */ me = BKE_mesh_from_object(ob); - if (!ED_mesh_pick_face(C, ob, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) { - return false; - } - - if (index >= me->totpoly) { - return false; - } - - mpoly_sel = me->mpoly + index; - if (mpoly_sel->flag & ME_HIDE) { - return false; + if (ED_mesh_pick_face(C, ob, mval, ED_MESH_PICK_DEFAULT_FACE_DIST, &index)) { + if (index < me->totpoly) { + mpoly_sel = me->mpoly + index; + if ((mpoly_sel->flag & ME_HIDE) == 0) { + found = true; + } + } } - /* clear flags */ - if (!extend && !deselect && !toggle) { - paintface_deselect_all_visible(C, ob, SEL_DESELECT, false); + if ((params->sel_op == SEL_OP_SET) && (found || params->deselect_all)) { + changed |= paintface_deselect_all_visible(C, ob, SEL_DESELECT, false); } - me->act_face = (int)index; + if (found) { + me->act_face = (int)index; - if (extend) { - mpoly_sel->flag |= ME_FACE_SEL; - } - else if (deselect) { - mpoly_sel->flag &= ~ME_FACE_SEL; - } - else if (toggle) { - if (mpoly_sel->flag & ME_FACE_SEL) { - mpoly_sel->flag &= ~ME_FACE_SEL; - } - else { - mpoly_sel->flag |= ME_FACE_SEL; + switch (params->sel_op) { + case SEL_OP_ADD: { + mpoly_sel->flag |= ME_FACE_SEL; + break; + } + case SEL_OP_SUB: { + mpoly_sel->flag &= ~ME_FACE_SEL; + break; + } + case SEL_OP_XOR: { + if (mpoly_sel->flag & ME_FACE_SEL) { + mpoly_sel->flag &= ~ME_FACE_SEL; + } + else { + mpoly_sel->flag |= ME_FACE_SEL; + } + break; + } + case SEL_OP_SET: { + mpoly_sel->flag |= ME_FACE_SEL; + break; + } + case SEL_OP_AND: { + BLI_assert_unreachable(); /* Doesn't make sense for picking. */ + break; + } } - } - else { - mpoly_sel->flag |= ME_FACE_SEL; - } - /* image window redraw */ + /* image window redraw */ - paintface_flush_flags(C, ob, SELECT); - ED_region_tag_redraw(CTX_wm_region(C)); /* XXX: should redraw all 3D views. */ - return true; + paintface_flush_flags(C, ob, SELECT); + ED_region_tag_redraw(CTX_wm_region(C)); /* XXX: should redraw all 3D views. */ + changed = true; + } + return changed || found; } void paintvert_flush_flags(Object *ob) diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c index dbda9fa7746..f2e7150e791 100644 --- a/source/blender/editors/mesh/editmesh_path.c +++ b/source/blender/editors/mesh/editmesh_path.c @@ -28,6 +28,7 @@ #include "ED_mesh.h" #include "ED_object.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_uvedit.h" #include "ED_view3d.h" @@ -700,7 +701,10 @@ static int edbm_shortest_path_pick_invoke(bContext *C, wmOperator *op, const wmE /* TODO(dfelinto): right now we try to find the closest element twice. * The ideal is to refactor EDBM_select_pick so it doesn't * have to pick the nearest vert/edge/face again. */ - EDBM_select_pick(C, event->mval, true, false, false); + const struct SelectPick_Params params = { + .sel_op = SEL_OP_ADD, + }; + EDBM_select_pick(C, event->mval, ¶ms); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 8784b1a90d9..4d73a0460b2 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -2016,7 +2016,7 @@ void MESH_OT_select_interior_faces(wmOperatorType *ot) * Gets called via generic mouse select operator. * \{ */ -bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) +bool EDBM_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params) { ViewContext vc; @@ -2033,100 +2033,148 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect uint bases_len = 0; Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(vc.view_layer, vc.v3d, &bases_len); - bool ok = false; + bool changed = false; + const bool found = unified_findnearest( + &vc, bases, bases_len, &base_index_active, &eve, &eed, &efa); - if (unified_findnearest(&vc, bases, bases_len, &base_index_active, &eve, &eed, &efa)) { + if ((params->sel_op == SEL_OP_SET) && (found || params->deselect_all)) { + /* Deselect everything. */ + for (uint base_index = 0; base_index < bases_len; base_index++) { + Base *base_iter = bases[base_index]; + Object *ob_iter = base_iter->object; + EDBM_flag_disable_all(BKE_editmesh_from_object(ob_iter), BM_ELEM_SELECT); + DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); + WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); + } + changed = true; + } + + if (found) { Base *basact = bases[base_index_active]; ED_view3d_viewcontext_init_object(&vc, basact->object); - /* Deselect everything */ - if (extend == false && deselect == false && toggle == false) { - for (uint base_index = 0; base_index < bases_len; base_index++) { - Base *base_iter = bases[base_index]; - Object *ob_iter = base_iter->object; - EDBM_flag_disable_all(BKE_editmesh_from_object(ob_iter), BM_ELEM_SELECT); - if (basact->object != ob_iter) { - DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob_iter->data); - } - } - } - if (efa) { - if (extend) { - /* set the last selected face */ - BM_mesh_active_face_set(vc.em->bm, efa); - - /* Work-around: deselect first, so we can guarantee it will */ - /* be active even if it was already selected */ - BM_select_history_remove(vc.em->bm, efa); - BM_face_select_set(vc.em->bm, efa, false); - BM_select_history_store(vc.em->bm, efa); - BM_face_select_set(vc.em->bm, efa, true); - } - else if (deselect) { - BM_select_history_remove(vc.em->bm, efa); - BM_face_select_set(vc.em->bm, efa, false); - } - else { - /* set the last selected face */ - BM_mesh_active_face_set(vc.em->bm, efa); + switch (params->sel_op) { + case SEL_OP_ADD: { + BM_mesh_active_face_set(vc.em->bm, efa); - if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + /* Work-around: deselect first, so we can guarantee it will + * be active even if it was already selected. */ + BM_select_history_remove(vc.em->bm, efa); + BM_face_select_set(vc.em->bm, efa, false); BM_select_history_store(vc.em->bm, efa); BM_face_select_set(vc.em->bm, efa, true); + break; } - else if (toggle) { + case SEL_OP_SUB: { BM_select_history_remove(vc.em->bm, efa); BM_face_select_set(vc.em->bm, efa, false); + break; + } + case SEL_OP_XOR: { + BM_mesh_active_face_set(vc.em->bm, efa); + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_select_history_store(vc.em->bm, efa); + BM_face_select_set(vc.em->bm, efa, true); + } + else { + BM_select_history_remove(vc.em->bm, efa); + BM_face_select_set(vc.em->bm, efa, false); + } + break; + } + case SEL_OP_SET: { + BM_mesh_active_face_set(vc.em->bm, efa); + if (!BM_elem_flag_test(efa, BM_ELEM_SELECT)) { + BM_select_history_store(vc.em->bm, efa); + BM_face_select_set(vc.em->bm, efa, true); + } + break; + } + case SEL_OP_AND: { + BLI_assert_unreachable(); /* Doesn't make sense for picking. */ + break; } } } else if (eed) { - if (extend) { - /* Work-around: deselect first, so we can guarantee it will */ - /* be active even if it was already selected */ - BM_select_history_remove(vc.em->bm, eed); - BM_edge_select_set(vc.em->bm, eed, false); - BM_select_history_store(vc.em->bm, eed); - BM_edge_select_set(vc.em->bm, eed, true); - } - else if (deselect) { - BM_select_history_remove(vc.em->bm, eed); - BM_edge_select_set(vc.em->bm, eed, false); - } - else { - if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + + switch (params->sel_op) { + case SEL_OP_ADD: { + /* Work-around: deselect first, so we can guarantee it will + * be active even if it was already selected. */ + BM_select_history_remove(vc.em->bm, eed); + BM_edge_select_set(vc.em->bm, eed, false); BM_select_history_store(vc.em->bm, eed); BM_edge_select_set(vc.em->bm, eed, true); + break; } - else if (toggle) { + case SEL_OP_SUB: { BM_select_history_remove(vc.em->bm, eed); BM_edge_select_set(vc.em->bm, eed, false); + break; + } + case SEL_OP_XOR: { + if (!BM_elem_flag_test(eed, BM_ELEM_SELECT)) { + BM_select_history_store(vc.em->bm, eed); + BM_edge_select_set(vc.em->bm, eed, true); + } + else { + BM_select_history_remove(vc.em->bm, eed); + BM_edge_select_set(vc.em->bm, eed, false); + } + break; + } + case SEL_OP_SET: { + if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + BM_select_history_store(vc.em->bm, eve); + BM_vert_select_set(vc.em->bm, eve, true); + } + break; + } + case SEL_OP_AND: { + BLI_assert_unreachable(); /* Doesn't make sense for picking. */ + break; } } } else if (eve) { - if (extend) { - /* Work-around: deselect first, so we can guarantee it will */ - /* be active even if it was already selected */ - BM_select_history_remove(vc.em->bm, eve); - BM_vert_select_set(vc.em->bm, eve, false); - BM_select_history_store(vc.em->bm, eve); - BM_vert_select_set(vc.em->bm, eve, true); - } - else if (deselect) { - BM_select_history_remove(vc.em->bm, eve); - BM_vert_select_set(vc.em->bm, eve, false); - } - else { - if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + switch (params->sel_op) { + case SEL_OP_ADD: { + /* Work-around: deselect first, so we can guarantee it will + * be active even if it was already selected. */ + BM_select_history_remove(vc.em->bm, eve); + BM_vert_select_set(vc.em->bm, eve, false); BM_select_history_store(vc.em->bm, eve); BM_vert_select_set(vc.em->bm, eve, true); + break; } - else if (toggle) { + case SEL_OP_SUB: { BM_select_history_remove(vc.em->bm, eve); BM_vert_select_set(vc.em->bm, eve, false); + break; + } + case SEL_OP_XOR: { + if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + BM_select_history_store(vc.em->bm, eve); + BM_vert_select_set(vc.em->bm, eve, true); + } + else { + BM_select_history_remove(vc.em->bm, eve); + BM_vert_select_set(vc.em->bm, eve, false); + } + break; + } + case SEL_OP_SET: { + if (!BM_elem_flag_test(eve, BM_ELEM_SELECT)) { + BM_select_history_store(vc.em->bm, eve); + BM_vert_select_set(vc.em->bm, eve, true); + } + break; + } + case SEL_OP_AND: { + BLI_assert_unreachable(); /* Doesn't make sense for picking. */ + break; } } } @@ -2168,12 +2216,12 @@ bool EDBM_select_pick(bContext *C, const int mval[2], bool extend, bool deselect DEG_id_tag_update(vc.obedit->data, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); - ok = true; + changed = true; } MEM_freeN(bases); - return ok; + return changed; } /** \} */ diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 54cc3efe986..10d121ffd32 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -57,6 +57,7 @@ #include "ED_object.h" #include "ED_outliner.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_transform.h" #include "ED_uvedit.h" #include "ED_view3d.h" @@ -8540,7 +8541,10 @@ static int edbm_point_normals_modal(bContext *C, wmOperator *op, const wmEvent * case EDBM_CLNOR_MODAL_POINTTO_SET_USE_SELECTED: new_mode = EDBM_CLNOR_POINTTO_MODE_COORDINATES; view3d_operator_needs_opengl(C); - if (EDBM_select_pick(C, event->mval, false, false, false)) { + const struct SelectPick_Params params = { + .sel_op = SEL_OP_SET, + }; + if (EDBM_select_pick(C, event->mval, ¶ms)) { /* Point to newly selected active. */ ED_object_calc_active_center_for_editmode(obedit, false, target); diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index 136d0d46c68..a19e2761394 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -736,7 +736,7 @@ void MBALL_OT_reveal_metaelems(wmOperatorType *ot) /** \name Select Pick Utility * \{ */ -bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) +bool ED_mball_select_pick(bContext *C, const int mval[2], const struct SelectPick_Params *params) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); static MetaElem *startelem = NULL; @@ -744,6 +744,8 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese int a, hits; GPUSelectResult buffer[MAXPICKELEMS]; rcti rect; + bool changed = false; + bool found = false; ED_view3d_viewcontext_init(C, &vc, depsgraph); @@ -822,7 +824,9 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese /* When some metaelem was found, then it is necessary to select or deselect it. */ if (ml_act) { - if (!extend && !deselect && !toggle) { + found = true; + + if (params->sel_op == SEL_OP_SET) { uint objects_len; Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data( vc.view_layer, vc.v3d, &objects_len); @@ -840,26 +844,36 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese MEM_freeN(objects); } - if (extend) { - ml_act->flag |= SELECT; - } - else if (deselect) { - ml_act->flag &= ~SELECT; - } - else if (toggle) { - if (ml_act->flag & SELECT) { + switch (params->sel_op) { + case SEL_OP_ADD: { + ml_act->flag |= SELECT; + break; + } + case SEL_OP_SUB: { ml_act->flag &= ~SELECT; + break; } - else { - ml_act->flag |= SELECT; + case SEL_OP_XOR: { + if (ml_act->flag & SELECT) { + ml_act->flag &= ~SELECT; + } + else { + ml_act->flag |= SELECT; + } + break; } - } - else { - /* Deselect all existing metaelems */ - BKE_mball_deselect_all(mb); + case SEL_OP_SET: { + /* Deselect all existing metaelems */ + BKE_mball_deselect_all(mb); - /* Select only metaelem clicked on */ - ml_act->flag |= SELECT; + /* Select only metaelem clicked on */ + ml_act->flag |= SELECT; + break; + } + case SEL_OP_AND: { + BLI_assert_unreachable(); /* Doesn't make sense for picking. */ + break; + } } mb->lastelem = ml_act; @@ -871,13 +885,18 @@ bool ED_mball_select_pick(bContext *C, const int mval[2], bool extend, bool dese ED_object_base_activate(C, base); } - return true; + changed = true; } } } FOREACH_BASE_IN_EDIT_MODE_END; - return false; + if (params->deselect_all && !found) { + ED_mball_deselect_all_multi(C); + changed = true; + } + + return changed || found; } /** \} */ diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index fc815ebe682..73885ab2a78 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -487,6 +487,8 @@ typedef struct PEData { int select_action; int select_toggle_action; bool is_changed; + + void *user_data; } PEData; static void PE_set_data(bContext *C, PEData *data) @@ -1721,46 +1723,6 @@ static void select_keys(PEData *data, point->flag |= PEP_EDIT_RECALC; } -static void extend_key_select(PEData *data, int point_index, int key_index, bool UNUSED(is_inside)) -{ - PTCacheEdit *edit = data->edit; - PTCacheEditPoint *point = edit->points + point_index; - PTCacheEditKey *key = point->keys + key_index; - - if ((key->flag & PEK_SELECT) == 0) { - key->flag |= PEK_SELECT; - point->flag |= PEP_EDIT_RECALC; - data->is_changed = true; - } -} - -static void deselect_key_select(PEData *data, - int point_index, - int key_index, - bool UNUSED(is_inside)) -{ - PTCacheEdit *edit = data->edit; - PTCacheEditPoint *point = edit->points + point_index; - PTCacheEditKey *key = point->keys + key_index; - - if ((key->flag & PEK_SELECT) != 0) { - key->flag &= ~PEK_SELECT; - point->flag |= PEP_EDIT_RECALC; - data->is_changed = true; - } -} - -static void toggle_key_select(PEData *data, int point_index, int key_index, bool UNUSED(is_inside)) -{ - PTCacheEdit *edit = data->edit; - PTCacheEditPoint *point = edit->points + point_index; - PTCacheEditKey *key = point->keys + key_index; - - key->flag ^= PEK_SELECT; - point->flag |= PEP_EDIT_RECALC; - data->is_changed = true; -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -1862,13 +1824,50 @@ void PARTICLE_OT_select_all(wmOperatorType *ot) /** \name Pick Select Operator * \{ */ -bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselect, bool toggle) +struct NearestParticleData { + PTCacheEditPoint *point; + PTCacheEditKey *key; +}; + +static void nearest_key_fn(PEData *data, int point_index, int key_index, bool UNUSED(is_inside)) +{ + PTCacheEdit *edit = data->edit; + PTCacheEditPoint *point = edit->points + point_index; + PTCacheEditKey *key = point->keys + key_index; + + struct NearestParticleData *user_data = data->user_data; + user_data->point = point; + user_data->key = key; + data->is_changed = true; +} + +static bool pe_nearest_point_and_key(bContext *C, + const int mval[2], + PTCacheEditPoint **r_point, + PTCacheEditKey **r_key) +{ + struct NearestParticleData user_data = {NULL}; + + PEData data; + PE_set_view3d_data(C, &data); + data.mval = mval; + data.rad = ED_view3d_select_dist_px(); + + data.user_data = &user_data; + for_mouse_hit_keys(&data, nearest_key_fn, PSEL_NEAREST); + bool found = data.is_changed; + PE_data_free(&data); + + *r_point = user_data.point; + *r_key = user_data.key; + return found; +} + +bool PE_mouse_particles(bContext *C, const int mval[2], const struct SelectPick_Params *params) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); - POINT_P; - KEY_K; PTCacheEdit *edit = PE_get_current(depsgraph, scene, ob); @@ -1876,39 +1875,61 @@ bool PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool desele return false; } - if (!extend && !deselect && !toggle) { - LOOP_VISIBLE_POINTS { - LOOP_SELECTED_KEYS { - key->flag &= ~PEK_SELECT; - point->flag |= PEP_EDIT_RECALC; - } - } - } + PTCacheEditPoint *point; + PTCacheEditKey *key; - PEData data; - PE_set_view3d_data(C, &data); - data.mval = mval; - data.rad = ED_view3d_select_dist_px(); + bool changed = false; + const bool found = pe_nearest_point_and_key(C, mval, &point, &key); - /* 1 = nearest only */ - if (extend) { - for_mouse_hit_keys(&data, extend_key_select, PSEL_NEAREST); - } - else if (deselect) { - for_mouse_hit_keys(&data, deselect_key_select, PSEL_NEAREST); - } - else { - for_mouse_hit_keys(&data, toggle_key_select, PSEL_NEAREST); + if ((params->sel_op == SEL_OP_SET) && (found || params->deselect_all)) { + changed |= PE_deselect_all_visible_ex(edit); } - if (data.is_changed) { - PE_update_selection(data.depsgraph, scene, ob, 1); - WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob); + if (found) { + switch (params->sel_op) { + case SEL_OP_ADD: { + if ((key->flag & PEK_SELECT) == 0) { + key->flag |= PEK_SELECT; + point->flag |= PEP_EDIT_RECALC; + changed = true; + } + break; + } + case SEL_OP_SUB: { + if ((key->flag & PEK_SELECT) != 0) { + key->flag &= ~PEK_SELECT; + point->flag |= PEP_EDIT_RECALC; + changed = true; + } + break; + } + case SEL_OP_XOR: { + key->flag ^= PEK_SELECT; + point->flag |= PEP_EDIT_RECALC; + changed = true; + break; + } + case SEL_OP_SET: { + if ((key->flag & PEK_SELECT) == 0) { + key->flag |= PEK_SELECT; + point->flag |= PEP_EDIT_RECALC; + changed = true; + } + break; + } + case SEL_OP_AND: { + BLI_assert_unreachable(); /* Doesn't make sense for picking. */ + break; + } + } } - PE_data_free(&data); + if (changed) { + PE_update_selection(depsgraph, scene, ob, 1); + WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob); + } - return true; + return changed || found; } /** \} */ diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 5d3168908d6..d1be7002c35 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1554,9 +1554,7 @@ static Base *object_mouse_select_menu(bContext *C, const GPUSelectResult *buffer, const int hits, const int mval[2], - bool extend, - bool deselect, - bool toggle) + const struct SelectPick_Params *params) { short baseCount = 0; bool ok; @@ -1625,9 +1623,9 @@ static Base *object_mouse_select_menu(bContext *C, PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); - RNA_boolean_set(&ptr, "extend", extend); - RNA_boolean_set(&ptr, "deselect", deselect); - RNA_boolean_set(&ptr, "toggle", toggle); + RNA_boolean_set(&ptr, "extend", params->sel_op == SEL_OP_ADD); + RNA_boolean_set(&ptr, "deselect", params->sel_op == SEL_OP_SUB); + RNA_boolean_set(&ptr, "toggle", params->sel_op == SEL_OP_XOR); WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, NULL); WM_operator_properties_free(&ptr); @@ -1638,9 +1636,12 @@ static Base *object_mouse_select_menu(bContext *C, static int bone_select_menu_exec(bContext *C, wmOperator *op) { const int name_index = RNA_enum_get(op->ptr, "name"); - const bool extend = RNA_boolean_get(op->ptr, "extend"); - const bool deselect = RNA_boolean_get(op->ptr, "deselect"); - const bool toggle = RNA_boolean_get(op->ptr, "toggle"); + + const struct SelectPick_Params params = { + .sel_op = ED_select_op_from_booleans(RNA_boolean_get(op->ptr, "extend"), + RNA_boolean_get(op->ptr, "deselect"), + RNA_boolean_get(op->ptr, "toggle")), + }; View3D *v3d = CTX_wm_view3d(C); ViewLayer *view_layer = CTX_data_view_layer(C); @@ -1656,12 +1657,11 @@ static int bone_select_menu_exec(bContext *C, wmOperator *op) if (basact->object->mode == OB_MODE_EDIT) { EditBone *ebone = (EditBone *)object_mouse_select_menu_data[name_index].item_ptr; - ED_armature_edit_select_pick_bone(C, basact, ebone, BONE_SELECTED, extend, deselect, toggle); + ED_armature_edit_select_pick_bone(C, basact, ebone, BONE_SELECTED, ¶ms); } else { bPoseChannel *pchan = (bPoseChannel *)object_mouse_select_menu_data[name_index].item_ptr; - ED_armature_pose_select_pick_bone( - view_layer, v3d, basact->object, pchan->bone, extend, deselect, toggle); + ED_armature_pose_select_pick_bone(view_layer, v3d, basact->object, pchan->bone, ¶ms); } /* Weak but ensures we activate the menu again before using the enum. */ @@ -1730,9 +1730,7 @@ static bool bone_mouse_select_menu(bContext *C, const GPUSelectResult *buffer, const int hits, const bool is_editmode, - const bool extend, - const bool deselect, - const bool toggle) + const struct SelectPick_Params *params) { BLI_assert(buffer); @@ -1848,9 +1846,9 @@ static bool bone_mouse_select_menu(bContext *C, PointerRNA ptr; WM_operator_properties_create_ptr(&ptr, ot); - RNA_boolean_set(&ptr, "extend", extend); - RNA_boolean_set(&ptr, "deselect", deselect); - RNA_boolean_set(&ptr, "toggle", toggle); + RNA_boolean_set(&ptr, "extend", params->sel_op == SEL_OP_ADD); + RNA_boolean_set(&ptr, "deselect", params->sel_op == SEL_OP_SUB); + RNA_boolean_set(&ptr, "toggle", params->sel_op == SEL_OP_XOR); WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr, NULL); WM_operator_properties_free(&ptr); @@ -2238,12 +2236,9 @@ static void deselect_all_tracks(MovieTracking *tracking) } } -/* mval is region coords */ static bool ed_object_select_pick(bContext *C, const int mval[2], - bool extend, - bool deselect, - bool toggle, + const struct SelectPick_Params *params, bool obcenter, bool enumerate, bool object) @@ -2290,7 +2285,7 @@ static bool ed_object_select_pick(bContext *C, /* NOTE: shift+alt goes to group-flush-selecting. */ if (enumerate) { - basact = object_mouse_select_menu(C, &vc, NULL, 0, mval, extend, deselect, toggle); + basact = object_mouse_select_menu(C, &vc, NULL, 0, mval, params); } else { base = startbase; @@ -2356,12 +2351,11 @@ static bool ed_object_select_pick(bContext *C, /* NOTE: shift+alt goes to group-flush-selecting. */ if (enumerate) { - if (has_bones && - bone_mouse_select_menu(C, buffer, hits, false, extend, deselect, toggle)) { + if (has_bones && bone_mouse_select_menu(C, buffer, hits, false, params)) { basact = NULL; } else { - basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, extend, deselect, toggle); + basact = object_mouse_select_menu(C, &vc, buffer, hits, mval, params); } } else { @@ -2388,6 +2382,7 @@ static bool ed_object_select_pick(bContext *C, * in height word, this buffer value belongs to camera. not to bundle */ if (hitresult & 0xFFFF0000) { + const bool extend = params->sel_op == SEL_OP_ADD; MovieTracking *tracking = &clip->tracking; ListBase *tracksbase; MovieTrackingTrack *track; @@ -2432,15 +2427,8 @@ static bool ed_object_select_pick(bContext *C, } } } - else if (ED_armature_pose_select_pick_with_buffer(view_layer, - v3d, - basact, - buffer, - hits, - extend, - deselect, - toggle, - do_nearest)) { + else if (ED_armature_pose_select_pick_with_buffer( + view_layer, v3d, basact, buffer, hits, params, do_nearest)) { /* then bone is found */ /* we make the armature selected: @@ -2502,6 +2490,22 @@ static bool ed_object_select_pick(bContext *C, /* Ensure code above doesn't change the active base. */ BLI_assert(oldbasact == (vc.obact ? BASACT(view_layer) : NULL)); + if (vc.obedit) { + /* Edit-mode, pass. */ + } + else if (is_pose_mode && (basact && (basact->object->mode & OB_MODE_POSE))) { + /* Pose-mode, pass (or moved into pose mode). */ + } + else { + /* Object-mode. */ + const bool found = (basact != NULL); + if ((params->sel_op == SEL_OP_SET) && (found || params->deselect_all)) { + /* `basact` may be NULL. */ + retval |= object_deselect_all_except(view_layer, basact); + DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); + } + } + /* so, do we have something selected? */ if (basact) { retval = true; @@ -2514,28 +2518,39 @@ static bool ed_object_select_pick(bContext *C, /* also prevent making it active on mouse selection */ else if (BASE_SELECTABLE(v3d, basact)) { const bool use_activate_selected_base = (oldbasact != basact) && (is_obedit == false); - if (extend) { - ED_object_base_select(basact, BA_SELECT); - } - else if (deselect) { - ED_object_base_select(basact, BA_DESELECT); - } - else if (toggle) { - if (basact->flag & BASE_SELECTED) { - /* Keep selected if the base is to be activated. */ - if (use_activate_selected_base == false) { - ED_object_base_select(basact, BA_DESELECT); + + switch (params->sel_op) { + case SEL_OP_ADD: { + ED_object_base_select(basact, BA_SELECT); + break; + } + case SEL_OP_SUB: { + ED_object_base_select(basact, BA_DESELECT); + break; + } + case SEL_OP_XOR: { + if (basact->flag & BASE_SELECTED) { + /* Keep selected if the base is to be activated. */ + if (use_activate_selected_base == false) { + ED_object_base_select(basact, BA_DESELECT); + } } + else { + ED_object_base_select(basact, BA_SELECT); + } + break; } - else { - ED_object_base_select(basact, BA_SELECT); + case SEL_OP_SET: { + /* When enabled, this puts other objects out of multi pose-mode. */ + if (is_pose_mode == false || (basact->object->mode & OB_MODE_POSE) == 0) { + object_deselect_all_except(view_layer, basact); + ED_object_base_select(basact, BA_SELECT); + } + break; } - } - else { - /* When enabled, this puts other objects out of multi pose-mode. */ - if (is_pose_mode == false || (basact->object->mode & OB_MODE_POSE) == 0) { - object_deselect_all_except(view_layer, basact); - ED_object_base_select(basact, BA_SELECT); + case SEL_OP_AND: { + BLI_assert_unreachable(); /* Doesn't make sense for picking. */ + break; } } @@ -2571,13 +2586,28 @@ static bool ed_object_select_pick(bContext *C, WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } + if (retval) { + if (vc.obact && vc.obact->mode & OB_MODE_POSE) { + ED_outliner_select_sync_from_pose_bone_tag(C); + } + else { + ED_outliner_select_sync_from_object_tag(C); + } + } + return retval; } -/* mouse selection in weight paint */ -/* gets called via generic mouse select operator */ -static bool ed_wpaint_vertex_select_pick( - bContext *C, const int mval[2], bool extend, bool deselect, bool toggle, Object *obact) +/** + * Mouse selection in weight paint. + * Called via generic mouse select operator. + * + * \return True when pick finds an element or the selection changed. + */ +static bool ed_wpaint_vertex_select_pick(bContext *C, + const int mval[2], + const struct SelectPick_Params *params, + Object *obact) { View3D *v3d = CTX_wm_view3d(C); const bool use_zbuf = !XRAY_ENABLED(v3d); @@ -2585,21 +2615,38 @@ static bool ed_wpaint_vertex_select_pick( Mesh *me = obact->data; /* already checked for NULL */ uint index = 0; MVert *mv; + bool changed = false; + + bool found = ED_mesh_pick_vert(C, obact, mval, ED_MESH_PICK_DEFAULT_VERT_DIST, use_zbuf, &index); - if (ED_mesh_pick_vert(C, obact, mval, ED_MESH_PICK_DEFAULT_VERT_DIST, use_zbuf, &index)) { + if ((params->sel_op == SEL_OP_SET) && (found || params->deselect_all)) { + changed |= paintface_deselect_all_visible(C, obact, SEL_DESELECT, false); + } + + if (found) { mv = &me->mvert[index]; - if (extend) { - mv->flag |= SELECT; - } - else if (deselect) { - mv->flag &= ~SELECT; - } - else if (toggle) { - mv->flag ^= SELECT; - } - else { - paintvert_deselect_all_visible(obact, SEL_DESELECT, false); - mv->flag |= SELECT; + switch (params->sel_op) { + case SEL_OP_ADD: { + mv->flag |= SELECT; + break; + } + case SEL_OP_SUB: { + mv->flag &= ~SELECT; + break; + } + case SEL_OP_XOR: { + mv->flag ^= SELECT; + break; + } + case SEL_OP_SET: { + paintvert_deselect_all_visible(obact, SEL_DESELECT, false); + mv->flag |= SELECT; + break; + } + case SEL_OP_AND: { + BLI_assert_unreachable(); /* Doesn't make sense for picking. */ + break; + } } /* update mselect */ @@ -2611,10 +2658,15 @@ static bool ed_wpaint_vertex_select_pick( } paintvert_flush_flags(obact); + + changed = true; + } + + if (changed) { paintvert_tag_select_update(C, obact); - return true; } - return false; + + return changed || found; } static int view3d_select_exec(bContext *C, wmOperator *op) @@ -2622,10 +2674,13 @@ static int view3d_select_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); Object *obact = CTX_data_active_object(C); - bool extend = RNA_boolean_get(op->ptr, "extend"); - bool deselect = RNA_boolean_get(op->ptr, "deselect"); - bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all"); - bool toggle = RNA_boolean_get(op->ptr, "toggle"); + const struct SelectPick_Params params = { + .sel_op = ED_select_op_from_booleans(RNA_boolean_get(op->ptr, "extend"), + RNA_boolean_get(op->ptr, "deselect"), + RNA_boolean_get(op->ptr, "toggle")), + .deselect_all = RNA_boolean_get(op->ptr, "deselect_all"), + + }; bool center = RNA_boolean_get(op->ptr, "center"); bool enumerate = RNA_boolean_get(op->ptr, "enumerate"); /* Only force object select for edit-mode to support vertex parenting, @@ -2656,10 +2711,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op) if (obedit && object == false) { if (obedit->type == OB_MESH) { - retval = EDBM_select_pick(C, location, extend, deselect, toggle); - if (!retval && deselect_all) { - retval = EDBM_mesh_deselect_all_multi(C); - } + retval = EDBM_select_pick(C, location, ¶ms); } else if (obedit->type == OB_ARMATURE) { if (enumerate) { @@ -2676,90 +2728,36 @@ static int view3d_select_exec(bContext *C, wmOperator *op) false, true, false); - retval = bone_mouse_select_menu(C, buffer, hits, true, extend, deselect, toggle); + retval = bone_mouse_select_menu(C, buffer, hits, true, ¶ms); } if (!retval) { - retval = ED_armature_edit_select_pick(C, location, extend, deselect, toggle); - } - - if (!retval && deselect_all) { - retval = ED_armature_edit_deselect_all_visible_multi(C); - } - if (retval) { - ED_outliner_select_sync_from_edit_bone_tag(C); + retval = ED_armature_edit_select_pick(C, location, ¶ms); } } else if (obedit->type == OB_LATTICE) { - retval = ED_lattice_select_pick(C, location, extend, deselect, toggle); - if (!retval && deselect_all) { - retval = ED_lattice_deselect_all_multi(C); - } + retval = ED_lattice_select_pick(C, location, ¶ms); } else if (ELEM(obedit->type, OB_CURVES_LEGACY, OB_SURF)) { - retval = ED_curve_editnurb_select_pick(C, location, extend, deselect, toggle); - if (!retval && deselect_all) { - retval = ED_curve_deselect_all_multi(C); - } + retval = ED_curve_editnurb_select_pick(C, location, ¶ms); } else if (obedit->type == OB_MBALL) { - retval = ED_mball_select_pick(C, location, extend, deselect, toggle); - if (!retval && deselect_all) { - retval = ED_mball_deselect_all_multi(C); - } + retval = ED_mball_select_pick(C, location, ¶ms); } else if (obedit->type == OB_FONT) { - retval = ED_curve_editfont_select_pick(C, location, extend, deselect, toggle); - if (!retval && deselect_all) { - /* pass */ - } - } - if (retval) { - WM_event_add_notifier(C, NC_GEOM | ND_SELECT, obedit->data); + retval = ED_curve_editfont_select_pick(C, location, ¶ms); } } else if (obact && obact->mode & OB_MODE_PARTICLE_EDIT) { - retval = PE_mouse_particles(C, location, extend, deselect, toggle); - if (!retval && deselect_all) { - retval = PE_deselect_all_visible(C); - } + retval = PE_mouse_particles(C, location, ¶ms); } else if (obact && BKE_paint_select_face_test(obact)) { - retval = paintface_mouse_select(C, obact, location, extend, deselect, toggle); - if (!retval && deselect_all) { - retval = paintface_deselect_all_visible(C, CTX_data_active_object(C), SEL_DESELECT, true); - } + retval = paintface_mouse_select(C, location, ¶ms, obact); } else if (BKE_paint_select_vert_test(obact)) { - retval = ed_wpaint_vertex_select_pick(C, location, extend, deselect, toggle, obact); - if (!retval && deselect_all) { - retval = paintvert_deselect_all_visible(obact, SEL_DESELECT, false); - if (retval) { - paintvert_tag_select_update(C, obact); - } - } + retval = ed_wpaint_vertex_select_pick(C, location, ¶ms, obact); } else { - retval = ed_object_select_pick( - C, location, extend, deselect, toggle, center, enumerate, object); - if (!retval && deselect_all) { - if (ED_pose_object_from_context(C)) { - retval = ED_pose_deselect_all_multi(C, SEL_DESELECT, false); - } - else { - retval = ED_object_base_deselect_all( - CTX_data_view_layer(C), CTX_wm_view3d(C), SEL_DESELECT); - DEG_id_tag_update(&scene->id, ID_RECALC_SELECT); - } - } - - if (retval) { - if (obact && obact->mode & OB_MODE_POSE) { - ED_outliner_select_sync_from_pose_bone_tag(C); - } - else { - ED_outliner_select_sync_from_object_tag(C); - } - } + retval = ed_object_select_pick(C, location, ¶ms, center, enumerate, object); } /* Pass-through allows tweaks diff --git a/source/blender/editors/util/select_utils.c b/source/blender/editors/util/select_utils.c index b6893c3032a..380c7ed0e43 100644 --- a/source/blender/editors/util/select_utils.c +++ b/source/blender/editors/util/select_utils.c @@ -112,3 +112,17 @@ bool ED_select_similar_compare_float_tree(const KDTree_1d *tree, return false; } + +eSelectOp ED_select_op_from_booleans(const bool extend, const bool deselect, const bool toggle) +{ + if (extend) { + return SEL_OP_ADD; + } + if (deselect) { + return SEL_OP_SUB; + } + if (toggle) { + return SEL_OP_XOR; + } + return SEL_OP_SET; +} |