From e88e80a6a0c8976ac2d245c274ca5a0388736743 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 14 Aug 2018 10:28:41 +1000 Subject: 3D View boarder/lasso select tool options Add tool options to control how select operates (add/sub/set/and/xor). Note: edit mode armature select still needs to support all options, this is complicated by how it handles partial end-point selection. --- .../blender/editors/animation/anim_channels_edit.c | 1 + source/blender/editors/animation/anim_markers.c | 1 + source/blender/editors/armature/armature_ops.c | 1 + source/blender/editors/armature/armature_select.c | 1 + source/blender/editors/armature/pose_select.c | 1 + source/blender/editors/curve/curve_ops.c | 1 + source/blender/editors/curve/editcurve_select.c | 1 + source/blender/editors/gpencil/gpencil_ops.c | 1 + source/blender/editors/gpencil/gpencil_select.c | 1 + source/blender/editors/include/ED_mesh.h | 2 +- source/blender/editors/include/ED_particle.h | 4 +- source/blender/editors/include/ED_sculpt.h | 2 +- source/blender/editors/include/ED_select_utils.h | 52 ++ .../blender/editors/lattice/editlattice_select.c | 1 + source/blender/editors/lattice/lattice_ops.c | 1 + source/blender/editors/mask/mask_add.c | 1 + source/blender/editors/mask/mask_edit.c | 1 + source/blender/editors/mask/mask_ops.c | 1 + source/blender/editors/mask/mask_select.c | 1 + source/blender/editors/mesh/editface.c | 18 +- source/blender/editors/mesh/editmesh_select.c | 1 + source/blender/editors/mesh/mesh_ops.c | 1 + source/blender/editors/metaball/mball_edit.c | 1 + source/blender/editors/metaball/mball_ops.c | 1 + source/blender/editors/object/object_ops.c | 1 + source/blender/editors/object/object_select.c | 1 + source/blender/editors/physics/particle_edit.c | 149 +++-- source/blender/editors/physics/physics_ops.c | 1 + source/blender/editors/sculpt_paint/paint_mask.c | 2 +- source/blender/editors/sculpt_paint/paint_ops.c | 5 +- source/blender/editors/space_action/action_ops.c | 1 + .../blender/editors/space_action/action_select.c | 1 + source/blender/editors/space_clip/clip_graph_ops.c | 1 + source/blender/editors/space_clip/space_clip.c | 1 + .../blender/editors/space_clip/tracking_select.c | 1 + source/blender/editors/space_graph/graph_ops.c | 1 + source/blender/editors/space_graph/graph_select.c | 1 + source/blender/editors/space_nla/nla_ops.c | 1 + source/blender/editors/space_nla/nla_select.c | 1 + source/blender/editors/space_node/node_ops.c | 1 + source/blender/editors/space_node/node_select.c | 1 + .../blender/editors/space_outliner/outliner_edit.c | 1 + .../blender/editors/space_outliner/outliner_ops.c | 1 + .../editors/space_sequencer/sequencer_ops.c | 1 + .../editors/space_sequencer/sequencer_select.c | 1 + source/blender/editors/space_view3d/view3d_ops.c | 5 +- .../blender/editors/space_view3d/view3d_select.c | 692 ++++++++++++--------- source/blender/editors/util/CMakeLists.txt | 4 +- source/blender/editors/util/select_utils.c | 70 +++ source/blender/editors/uvedit/uvedit_ops.c | 1 + source/blender/windowmanager/WM_api.h | 10 +- .../windowmanager/gizmo/intern/wm_gizmo_map.c | 1 + .../blender/windowmanager/intern/wm_gesture_ops.c | 19 +- .../windowmanager/intern/wm_operator_props.c | 16 + 54 files changed, 706 insertions(+), 383 deletions(-) create mode 100644 source/blender/editors/include/ED_select_utils.h create mode 100644 source/blender/editors/util/select_utils.c (limited to 'source/blender') diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 3f22ac6fa3a..a6eb9c5f3b5 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -67,6 +67,7 @@ #include "ED_keyframes_edit.h" // XXX move the select modes out of there! #include "ED_object.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index e1f4092c494..fe6c36d4cdb 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -71,6 +71,7 @@ #include "ED_anim_api.h" #include "ED_markers.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_util.h" #include "ED_numinput.h" #include "ED_object.h" diff --git a/source/blender/editors/armature/armature_ops.c b/source/blender/editors/armature/armature_ops.c index 039bb7f1847..d43d051deba 100644 --- a/source/blender/editors/armature/armature_ops.c +++ b/source/blender/editors/armature/armature_ops.c @@ -35,6 +35,7 @@ #include "ED_armature.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_transform.h" #include "armature_intern.h" diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index 7602bccc48c..365771a1430 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -55,6 +55,7 @@ #include "ED_armature.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_view3d.h" #include "DEG_depsgraph.h" diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 72f0c68f660..621b20c0ca7 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -60,6 +60,7 @@ #include "ED_mesh.h" #include "ED_object.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_view3d.h" #include "armature_intern.h" diff --git a/source/blender/editors/curve/curve_ops.c b/source/blender/editors/curve/curve_ops.c index 925358b5304..2cfbc2f44c6 100644 --- a/source/blender/editors/curve/curve_ops.c +++ b/source/blender/editors/curve/curve_ops.c @@ -44,6 +44,7 @@ #include "ED_curve.h" #include "ED_object.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_transform.h" #include "curve_intern.h" diff --git a/source/blender/editors/curve/editcurve_select.c b/source/blender/editors/curve/editcurve_select.c index 0fae39776a9..7fcf7e073dc 100644 --- a/source/blender/editors/curve/editcurve_select.c +++ b/source/blender/editors/curve/editcurve_select.c @@ -49,6 +49,7 @@ #include "WM_types.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_types.h" #include "ED_view3d.h" #include "ED_curve.h" diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index b2e1758b169..1f238fccdc4 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -50,6 +50,7 @@ #include "RNA_access.h" #include "ED_gpencil.h" +#include "ED_select_utils.h" #include "ED_object.h" #include "ED_transform.h" diff --git a/source/blender/editors/gpencil/gpencil_select.c b/source/blender/editors/gpencil/gpencil_select.c index 3e0caa8d5d8..401a4e2a550 100644 --- a/source/blender/editors/gpencil/gpencil_select.c +++ b/source/blender/editors/gpencil/gpencil_select.c @@ -62,6 +62,7 @@ #include "UI_view2d.h" #include "ED_gpencil.h" +#include "ED_select_utils.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index a473974eb3f..d791c055d95 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -204,7 +204,7 @@ void EMBM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct BMEd /* editface.c */ void paintface_flush_flags(struct Object *ob, short flag); bool paintface_mouse_select(struct bContext *C, struct Object *ob, const int mval[2], bool extend, bool deselect, bool toggle); -int do_paintface_box_select(struct ViewContext *vc, struct rcti *rect, bool select, bool extend); +int do_paintface_box_select(struct ViewContext *vc, struct rcti *rect, int sel_op); void paintface_deselect_all_visible(struct Object *ob, int action, bool flush_flags); void paintface_select_linked(struct bContext *C, struct Object *ob, const int mval[2], const bool select); bool paintface_minmax(struct Object *ob, float r_min[3], float r_max[3]); diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h index 08ed8097ea6..552975b9e55 100644 --- a/source/blender/editors/include/ED_particle.h +++ b/source/blender/editors/include/ED_particle.h @@ -62,9 +62,9 @@ void PE_update_object( /* selection tools */ int PE_mouse_particles(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); -int PE_border_select(struct bContext *C, const struct rcti *rect, bool select, bool extend); +int PE_border_select(struct bContext *C, const struct rcti *rect, const int sel_op); int PE_circle_select(struct bContext *C, int selecting, const int mval[2], float rad); -int PE_lasso_select(struct bContext *C, const int mcords[][2], const short moves, bool extend, bool select); +int PE_lasso_select(struct bContext *C, const int mcords[][2], const short moves, const int sel_op); void PE_deselect_all_visible(struct PTCacheEdit *edit); /* particle_edit_undo.c */ diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h index c624405cd0c..94508a98dcb 100644 --- a/source/blender/editors/include/ED_sculpt.h +++ b/source/blender/editors/include/ED_sculpt.h @@ -43,7 +43,7 @@ struct ListBase; /* sculpt.c */ void ED_operatortypes_sculpt(void); void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *ar, struct Object *ob); -int ED_sculpt_mask_box_select(struct bContext *C, struct ViewContext *vc, const struct rcti *rect, bool select, bool extend); +int ED_sculpt_mask_box_select(struct bContext *C, struct ViewContext *vc, const struct rcti *rect, bool select); /* sculpt_undo.c */ void ED_sculpt_undosys_type(struct UndoType *ut); diff --git a/source/blender/editors/include/ED_select_utils.h b/source/blender/editors/include/ED_select_utils.h new file mode 100644 index 00000000000..add1c812e1f --- /dev/null +++ b/source/blender/editors/include/ED_select_utils.h @@ -0,0 +1,52 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file ED_select_utils.h + * \ingroup editors + */ + +#ifndef __ED_SELECT_UTILS_H__ +#define __ED_SELECT_UTILS_H__ + +enum { + SEL_TOGGLE = 0, + SEL_SELECT = 1, + SEL_DESELECT = 2, + SEL_INVERT = 3, +}; + +/** See #WM_operator_properties_select_operation */ +typedef enum { + SEL_OP_ADD = 1, + SEL_OP_SUB, + SEL_OP_SET, + SEL_OP_AND, + SEL_OP_XOR, +} eSelectOp; + +#define SEL_OP_USE_OUTSIDE(sel_op) (ELEM(sel_op, SEL_OP_AND)) +#define SEL_OP_USE_PRE_DESELECT(sel_op) (ELEM(sel_op, SEL_OP_SET)) +#define SEL_OP_CAN_DESELECT(sel_op) (!ELEM(sel_op, SEL_OP_ADD)) + +/* Use when we've de-selected all first for 'SEL_OP_SET' */ +int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool is_inside); +int ED_select_op_action_deselected(const eSelectOp sel_op, const bool is_select, const bool is_inside); + +#endif /* __ED_SELECT_UTILS_H__ */ diff --git a/source/blender/editors/lattice/editlattice_select.c b/source/blender/editors/lattice/editlattice_select.c index 6f1c864130d..41ed73baf0e 100644 --- a/source/blender/editors/lattice/editlattice_select.c +++ b/source/blender/editors/lattice/editlattice_select.c @@ -53,6 +53,7 @@ #include "BKE_layer.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_lattice.h" #include "ED_view3d.h" diff --git a/source/blender/editors/lattice/lattice_ops.c b/source/blender/editors/lattice/lattice_ops.c index e7d9fc146ce..593b880e501 100644 --- a/source/blender/editors/lattice/lattice_ops.c +++ b/source/blender/editors/lattice/lattice_ops.c @@ -36,6 +36,7 @@ #include "WM_types.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_object.h" #include "ED_lattice.h" diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index ad1a567f843..df07326c590 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -45,6 +45,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "ED_select_utils.h" #include "ED_mask.h" /* own include */ #include "ED_screen.h" diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c index 7d5fc5126ef..060778cefc9 100644 --- a/source/blender/editors/mask/mask_edit.c +++ b/source/blender/editors/mask/mask_edit.c @@ -42,6 +42,7 @@ #include "WM_types.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_mask.h" /* own include */ #include "ED_image.h" #include "ED_object.h" /* ED_keymap_proportional_maskmode only */ diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index a93ef4405dc..cb90d0a4888 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -52,6 +52,7 @@ #include "ED_keyframing.h" #include "ED_mask.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "RNA_access.h" #include "RNA_define.h" diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c index 8559be67ece..530b7bd968c 100644 --- a/source/blender/editors/mask/mask_select.c +++ b/source/blender/editors/mask/mask_select.c @@ -45,6 +45,7 @@ #include "WM_types.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_mask.h" /* own include */ #include "RNA_access.h" diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index dde66b8aa13..6c126551228 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -46,6 +46,7 @@ #include "ED_mesh.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_view3d.h" #include "WM_api.h" @@ -391,7 +392,7 @@ bool paintface_mouse_select(struct bContext *C, Object *ob, const int mval[2], b return true; } -int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool extend) +int do_paintface_box_select(ViewContext *vc, rcti *rect, int sel_op) { Object *ob = vc->obact; Mesh *me; @@ -412,7 +413,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten selar = MEM_callocN(me->totpoly + 1, "selar"); - if (extend == false && select) { + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { paintface_deselect_all_visible(vc->obact, SEL_DESELECT, false); } @@ -439,13 +440,12 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten mpoly = me->mpoly; for (a = 1; a <= me->totpoly; a++, mpoly++) { - if (selar[a]) { - if (mpoly->flag & ME_HIDE) { - /* pass */ - } - else { - if (select) mpoly->flag |= ME_FACE_SEL; - else mpoly->flag &= ~ME_FACE_SEL; + if ((mpoly->flag & ME_HIDE) == 0) { + const bool is_select = mpoly->flag & ME_FACE_SEL; + const bool is_inside = (selar[a] != 0); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(mpoly->flag, sel_op_result, ME_FACE_SEL); } } } diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index cdb8981801a..8c3c9df54dd 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -59,6 +59,7 @@ #include "ED_mesh.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_view3d.h" #include "DNA_mesh_types.h" diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 842a1ecab35..9419caa4d65 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -40,6 +40,7 @@ #include "ED_object.h" #include "ED_mesh.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "mesh_intern.h" /* own include */ diff --git a/source/blender/editors/metaball/mball_edit.c b/source/blender/editors/metaball/mball_edit.c index 1ae122a3801..06add39d90f 100644 --- a/source/blender/editors/metaball/mball_edit.c +++ b/source/blender/editors/metaball/mball_edit.c @@ -55,6 +55,7 @@ #include "ED_mball.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_view3d.h" #include "WM_api.h" diff --git a/source/blender/editors/metaball/mball_ops.c b/source/blender/editors/metaball/mball_ops.c index ab7098eeb53..09d1b3a3ed8 100644 --- a/source/blender/editors/metaball/mball_ops.c +++ b/source/blender/editors/metaball/mball_ops.c @@ -37,6 +37,7 @@ #include "ED_mball.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_object.h" #include "mball_intern.h" diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index ac2eb60456f..fd65867a246 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -46,6 +46,7 @@ #include "WM_types.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_object.h" #include "DEG_depsgraph.h" diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index c23a1d64ee8..3ebec65da69 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -72,6 +72,7 @@ #include "ED_object.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_keyframing.h" #include "UI_interface.h" diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 6ce3e7c06c6..26fbdaf4566 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -75,6 +75,7 @@ #include "ED_mesh.h" #include "ED_particle.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_view3d.h" #include "GPU_immediate.h" @@ -418,6 +419,7 @@ typedef struct PEData { float dist; float dval; int select; + eSelectOp sel_op; float *dvec; float combfac; @@ -610,10 +612,15 @@ static bool point_is_selected(PTCacheEditPoint *point) /*************************** iterators *******************************/ typedef void (*ForPointFunc)(PEData *data, int point_index); -typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index); +typedef void (*ForKeyFunc)(PEData *data, int point_index, int key_index, bool is_inside); typedef void (*ForKeyMatFunc)(PEData *data, float mat[4][4], float imat[4][4], int point_index, int key_index, PTCacheEditKey *key); -static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, bool nearest) +enum eParticleSelectFlag { + PSEL_NEAREST = (1 << 0), + PSEL_ALL_KEYS = (1 << 1), +}; + +static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, const enum eParticleSelectFlag flag) { ParticleEditSettings *pset = PE_settings(data->scene); PTCacheEdit *edit = data->edit; @@ -634,34 +641,45 @@ static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, bool nearest) /* only do end keys */ key = point->keys + point->totkey - 1; - if (nearest) { + if (flag & PSEL_NEAREST) { if (key_inside_circle(data, dist, KEY_WCO, &dist)) { nearest_point = p; nearest_key = point->totkey - 1; } } - else if (key_inside_test(data, KEY_WCO)) - func(data, p, point->totkey - 1); + else { + const bool is_inside = key_inside_test(data, KEY_WCO); + if (is_inside || (flag & PSEL_ALL_KEYS)) { + func(data, p, point->totkey - 1, is_inside); + } + } } } else { /* do all keys */ LOOP_VISIBLE_KEYS { - if (nearest) { + if (flag & PSEL_NEAREST) { if (key_inside_circle(data, dist, KEY_WCO, &dist)) { nearest_point = p; nearest_key = k; } } - else if (key_inside_test(data, KEY_WCO)) - func(data, p, k); + else { + const bool is_inside = key_inside_test(data, KEY_WCO); + if (is_inside || (flag & PSEL_ALL_KEYS)) { + func(data, p, k, is_inside); + } + } } } } /* do nearest only */ - if (nearest && nearest_point > -1) - func(data, nearest_point, nearest_key); + if (flag & PSEL_NEAREST) { + if (nearest_point != -1) { + func(data, nearest_point, nearest_key, true); + } + } } static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selected) @@ -797,7 +815,7 @@ static void foreach_selected_key(PEData *data, ForKeyFunc func) LOOP_VISIBLE_POINTS { LOOP_SELECTED_KEYS { - func(data, p, k); + func(data, p, k, true); } } } @@ -1496,7 +1514,7 @@ void PE_update_object(Depsgraph *depsgraph, Scene *scene, Object *ob, int usefla /*-----selection callbacks-----*/ -static void select_key(PEData *data, int point_index, int key_index) +static void select_key(PEData *data, int point_index, int key_index, bool UNUSED(is_inside)) { PTCacheEdit *edit = data->edit; PTCacheEditPoint *point = edit->points + point_index; @@ -1510,7 +1528,20 @@ static void select_key(PEData *data, int point_index, int key_index) point->flag |= PEP_EDIT_RECALC; } -static void select_keys(PEData *data, int point_index, int UNUSED(key_index)) +static void select_key_op(PEData *data, int point_index, int key_index, bool is_inside) +{ + PTCacheEdit *edit = data->edit; + PTCacheEditPoint *point = edit->points + point_index; + PTCacheEditKey *key = point->keys + key_index; + const bool is_select = key->flag & PEK_SELECT; + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT); + point->flag |= PEP_EDIT_RECALC; + } +} + +static void select_keys(PEData *data, int point_index, int UNUSED(key_index), bool UNUSED(is_inside)) { PTCacheEdit *edit = data->edit; PTCacheEditPoint *point = edit->points + point_index; @@ -1526,7 +1557,7 @@ static void select_keys(PEData *data, int point_index, int UNUSED(key_index)) point->flag |= PEP_EDIT_RECALC; } -static void extend_key_select(PEData *data, int point_index, int key_index) +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; @@ -1536,7 +1567,7 @@ static void extend_key_select(PEData *data, int point_index, int key_index) point->flag |= PEP_EDIT_RECALC; } -static void deselect_key_select(PEData *data, int point_index, int key_index) +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; @@ -1546,7 +1577,7 @@ static void deselect_key_select(PEData *data, int point_index, int key_index) point->flag |= PEP_EDIT_RECALC; } -static void toggle_key_select(PEData *data, int point_index, int key_index) +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; @@ -1664,12 +1695,15 @@ int PE_mouse_particles(bContext *C, const int mval[2], bool extend, bool deselec data.rad = ED_view3d_select_dist_px(); /* 1 = nearest only */ - if (extend) - for_mouse_hit_keys(&data, extend_key_select, true); - else if (deselect) - for_mouse_hit_keys(&data, deselect_key_select, true); - else - for_mouse_hit_keys(&data, toggle_key_select, true); + 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); + } PE_update_selection(data.depsgraph, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob); @@ -1900,7 +1934,7 @@ static int select_linked_exec(bContext *C, wmOperator *op) data.rad = 75.0f; data.select = !RNA_boolean_get(op->ptr, "deselect"); - for_mouse_hit_keys(&data, select_keys, true); + for_mouse_hit_keys(&data, select_keys, PSEL_NEAREST); PE_update_selection(data.depsgraph, data.scene, data.ob, 1); WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob); @@ -1946,7 +1980,7 @@ void PE_deselect_all_visible(PTCacheEdit *edit) } } -int PE_border_select(bContext *C, const rcti *rect, bool select, bool extend) +int PE_border_select(bContext *C, const rcti *rect, const int sel_op) { Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); @@ -1956,14 +1990,15 @@ int PE_border_select(bContext *C, const rcti *rect, bool select, bool extend) if (!PE_start_edit(edit)) return OPERATOR_CANCELLED; - if (extend == 0 && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { PE_deselect_all_visible(edit); + } PE_set_view3d_data(C, &data); data.rect = rect; - data.select = select; + data.sel_op = sel_op; - for_mouse_hit_keys(&data, select_key, false); + for_mouse_hit_keys(&data, select_key_op, PSEL_ALL_KEYS); PE_update_selection(data.depsgraph, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob); @@ -1988,7 +2023,7 @@ int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad) data.rad = rad; data.select = selecting; - for_mouse_hit_keys(&data, select_key, false); + for_mouse_hit_keys(&data, select_key, 0); PE_update_selection(data.depsgraph, scene, ob, 1); WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob); @@ -1998,7 +2033,7 @@ int PE_circle_select(bContext *C, int selecting, const int mval[2], float rad) /************************ lasso select operator ************************/ -int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool extend, bool select) +int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, const int sel_op) { Scene *scene = CTX_data_scene(C); Object *ob = CTX_data_active_object(C); @@ -2018,8 +2053,9 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool if (!PE_start_edit(edit)) return OPERATOR_CANCELLED; - if (extend == 0 && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { PE_deselect_all_visible(edit); + } /* only for depths */ PE_set_view3d_data(C, &data); @@ -2032,47 +2068,32 @@ int PE_lasso_select(bContext *C, const int mcords[][2], const short moves, bool LOOP_KEYS { copy_v3_v3(co, key->co); mul_m4_v3(mat, co); - if ((ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) && - BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) && - key_test_depth(&data, co, screen_co)) - { - if (select) { - if (!(key->flag & PEK_SELECT)) { - key->flag |= PEK_SELECT; - point->flag |= PEP_EDIT_RECALC; - } - } - else { - if (key->flag & PEK_SELECT) { - key->flag &= ~PEK_SELECT; - point->flag |= PEP_EDIT_RECALC; - } - } + const bool is_select = key->flag & PEK_SELECT; + const bool is_inside = ( + (ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) && + BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) && + key_test_depth(&data, co, screen_co)); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT); + point->flag |= PEP_EDIT_RECALC; } } } else if (pset->selectmode == SCE_SELECT_END) { if (point->totkey) { key = point->keys + point->totkey - 1; - copy_v3_v3(co, key->co); mul_m4_v3(mat, co); - if ((ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) && - BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) && - key_test_depth(&data, co, screen_co)) - { - if (select) { - if (!(key->flag & PEK_SELECT)) { - key->flag |= PEK_SELECT; - point->flag |= PEP_EDIT_RECALC; - } - } - else { - if (key->flag & PEK_SELECT) { - key->flag &= ~PEK_SELECT; - point->flag |= PEP_EDIT_RECALC; - } - } + const bool is_select = key->flag & PEK_SELECT; + const bool is_inside = ( + (ED_view3d_project_int_global(ar, co, screen_co, V3D_PROJ_TEST_CLIP_WIN) == V3D_PROJ_RET_OK) && + BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) && + key_test_depth(&data, co, screen_co)); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT); + point->flag |= PEP_EDIT_RECALC; } } } @@ -2944,7 +2965,7 @@ static void set_delete_particle(PEData *data, int pa_index) edit->points[pa_index].flag |= PEP_TAG; } -static void set_delete_particle_key(PEData *data, int pa_index, int key_index) +static void set_delete_particle_key(PEData *data, int pa_index, int key_index, bool UNUSED(is_inside)) { PTCacheEdit *edit = data->edit; diff --git a/source/blender/editors/physics/physics_ops.c b/source/blender/editors/physics/physics_ops.c index a1a61b08dc9..a41033bf47d 100644 --- a/source/blender/editors/physics/physics_ops.c +++ b/source/blender/editors/physics/physics_ops.c @@ -34,6 +34,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "ED_select_utils.h" #include "ED_physics.h" #include "ED_object.h" diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index aed48aef3a9..a09c04f6fb0 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -258,7 +258,7 @@ static void mask_box_select_task_cb( } BKE_pbvh_vertex_iter_end; } -int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *rect, bool select, bool UNUSED(extend)) +int ED_sculpt_mask_box_select(struct bContext *C, ViewContext *vc, const rcti *rect, bool select) { Depsgraph *depsgraph = CTX_data_depsgraph(C); Sculpt *sd = vc->scene->toolsettings->sculpt; diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 86d36ade477..359c93175b4 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -48,6 +48,7 @@ #include "ED_paint.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_image.h" #include "ED_gpencil.h" #include "UI_resources.h" @@ -1444,9 +1445,9 @@ void ED_keymap_paint(wmKeyConfig *keyconf) RNA_enum_set(kmi->ptr, "action", SEL_INVERT); WM_keymap_add_item(keymap, "VIEW3D_OT_select_border", BKEY, KM_PRESS, 0, 0); kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); - RNA_boolean_set(kmi->ptr, "deselect", false); + RNA_enum_set(kmi->ptr, "mode", SEL_OP_ADD); kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL, 0); - RNA_boolean_set(kmi->ptr, "deselect", true); + RNA_enum_set(kmi->ptr, "mode", SEL_OP_SUB); WM_keymap_add_item(keymap, "VIEW3D_OT_select_circle", CKEY, KM_PRESS, 0, 0); /* Image/Texture Paint mode */ diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index a4b96e76066..a53561f814d 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -40,6 +40,7 @@ #include "ED_markers.h" #include "ED_transform.h" #include "ED_object.h" +#include "ED_select_utils.h" #include "action_intern.h" diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index 831c461538a..ca671078a82 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -62,6 +62,7 @@ #include "ED_keyframes_edit.h" #include "ED_markers.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/editors/space_clip/clip_graph_ops.c b/source/blender/editors/space_clip/clip_graph_ops.c index b5a0e374431..5b51f70c447 100644 --- a/source/blender/editors/space_clip/clip_graph_ops.c +++ b/source/blender/editors/space_clip/clip_graph_ops.c @@ -44,6 +44,7 @@ #include "WM_types.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_clip.h" #include "RNA_access.h" diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 4f9fd9c65d7..24033b4f468 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -55,6 +55,7 @@ #include "ED_mask.h" #include "ED_space_api.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_clip.h" #include "ED_transform.h" #include "ED_uvedit.h" /* just for ED_image_draw_cursor */ diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index cf4687dca31..58bf8a50416 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -46,6 +46,7 @@ #include "WM_types.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_clip.h" #include "RNA_access.h" diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 54b35b6acb6..d796c9be3b6 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -48,6 +48,7 @@ #include "ED_anim_api.h" #include "ED_markers.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_transform.h" #include "ED_object.h" diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index e91bb192d3c..3b2ff4266b7 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -56,6 +56,7 @@ #include "ED_anim_api.h" #include "ED_keyframes_edit.h" #include "ED_markers.h" +#include "ED_select_utils.h" #include "WM_api.h" #include "WM_types.h" diff --git a/source/blender/editors/space_nla/nla_ops.c b/source/blender/editors/space_nla/nla_ops.c index 8a776ad32e9..53a9c8a0dd2 100644 --- a/source/blender/editors/space_nla/nla_ops.c +++ b/source/blender/editors/space_nla/nla_ops.c @@ -39,6 +39,7 @@ #include "ED_anim_api.h" #include "ED_markers.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_transform.h" #include "WM_api.h" diff --git a/source/blender/editors/space_nla/nla_select.c b/source/blender/editors/space_nla/nla_select.c index 5d32b23ad67..6d03354c165 100644 --- a/source/blender/editors/space_nla/nla_select.c +++ b/source/blender/editors/space_nla/nla_select.c @@ -46,6 +46,7 @@ #include "ED_anim_api.h" #include "ED_keyframes_edit.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "RNA_access.h" #include "RNA_define.h" diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.c index dccc999b2d1..142d6fdc237 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.c @@ -37,6 +37,7 @@ #include "ED_node.h" /* own include */ #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_transform.h" #include "RNA_access.h" diff --git a/source/blender/editors/space_node/node_select.c b/source/blender/editors/space_node/node_select.c index 636ed755cb1..ed119f34aa5 100644 --- a/source/blender/editors/space_node/node_select.c +++ b/source/blender/editors/space_node/node_select.c @@ -45,6 +45,7 @@ #include "ED_node.h" /* own include */ #include "ED_screen.h" +#include "ED_select_utils.h" #include "RNA_access.h" #include "RNA_define.h" diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index e895ff53bc5..ec267d333a7 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -71,6 +71,7 @@ #include "ED_object.h" #include "ED_outliner.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_keyframing.h" #include "ED_armature.h" diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 34d79ea5a61..39d77f75c0e 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -52,6 +52,7 @@ #include "WM_types.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "outliner_intern.h" diff --git a/source/blender/editors/space_sequencer/sequencer_ops.c b/source/blender/editors/space_sequencer/sequencer_ops.c index f60bd98c4d6..14e181f2a25 100644 --- a/source/blender/editors/space_sequencer/sequencer_ops.c +++ b/source/blender/editors/space_sequencer/sequencer_ops.c @@ -39,6 +39,7 @@ #include "ED_sequencer.h" #include "ED_markers.h" #include "ED_transform.h" /* transform keymap */ +#include "ED_select_utils.h" #include "BKE_sequencer.h" diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c index c440d12e444..5506ccf249a 100644 --- a/source/blender/editors/space_sequencer/sequencer_select.c +++ b/source/blender/editors/space_sequencer/sequencer_select.c @@ -50,6 +50,7 @@ #include "ED_screen.h" #include "ED_sequencer.h" +#include "ED_select_utils.h" #include "UI_view2d.h" diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index cf9b8afe8e5..c1f5f33b38c 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -57,6 +57,7 @@ #include "WM_types.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_transform.h" #include "view3d_intern.h" @@ -487,9 +488,9 @@ void view3d_keymap(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "VIEW3D_OT_select_border", BKEY, KM_PRESS, 0, 0); kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); - RNA_boolean_set(kmi->ptr, "deselect", false); + RNA_enum_set(kmi->ptr, "mode", SEL_OP_ADD); kmi = WM_keymap_add_item(keymap, "VIEW3D_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_SHIFT | KM_CTRL, 0); - RNA_boolean_set(kmi->ptr, "deselect", true); + RNA_enum_set(kmi->ptr, "mode", SEL_OP_SUB); WM_keymap_add_item(keymap, "VIEW3D_OT_select_circle", CKEY, KM_PRESS, 0, 0); WM_keymap_add_item(keymap, "VIEW3D_OT_clip_border", BKEY, KM_PRESS, KM_ALT, 0); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 10ea290574b..3181b72ac51 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -95,6 +95,7 @@ #include "ED_mesh.h" #include "ED_object.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_sculpt.h" #include "ED_mball.h" #include "ED_gpencil.h" @@ -149,7 +150,7 @@ void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact) /* local prototypes */ -static void edbm_backbuf_check_and_select_verts(BMEditMesh *em, const bool select) +static void edbm_backbuf_check_and_select_verts(BMEditMesh *em, const eSelectOp sel_op) { BMVert *eve; BMIter iter; @@ -157,15 +158,18 @@ static void edbm_backbuf_check_and_select_verts(BMEditMesh *em, const bool selec BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - if (EDBM_backbuf_check(index)) { - BM_vert_select_set(em->bm, eve, select); + const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT); + const bool is_inside = EDBM_backbuf_check(index); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_vert_select_set(em->bm, eve, sel_op_result); } } index++; } } -static void edbm_backbuf_check_and_select_edges(BMEditMesh *em, const bool select) +static void edbm_backbuf_check_and_select_edges(BMEditMesh *em, const eSelectOp sel_op) { BMEdge *eed; BMIter iter; @@ -173,15 +177,18 @@ static void edbm_backbuf_check_and_select_edges(BMEditMesh *em, const bool selec BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) { if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - if (EDBM_backbuf_check(index)) { - BM_edge_select_set(em->bm, eed, select); + const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); + const bool is_inside = EDBM_backbuf_check(index); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_edge_select_set(em->bm, eed, sel_op_result); } } index++; } } -static void edbm_backbuf_check_and_select_faces(BMEditMesh *em, const bool select) +static void edbm_backbuf_check_and_select_faces(BMEditMesh *em, const eSelectOp sel_op) { BMFace *efa; BMIter iter; @@ -189,26 +196,31 @@ static void edbm_backbuf_check_and_select_faces(BMEditMesh *em, const bool selec BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) { if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - if (EDBM_backbuf_check(index)) { - BM_face_select_set(em->bm, efa, select); + const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); + const bool is_inside = EDBM_backbuf_check(index); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_face_select_set(em->bm, efa, sel_op_result); } } index++; } } - /* object mode, edbm_ prefix is confusing here, rename? */ -static void edbm_backbuf_check_and_select_verts_obmode(Mesh *me, const bool select) +static void edbm_backbuf_check_and_select_verts_obmode(Mesh *me, const eSelectOp sel_op) { MVert *mv = me->mvert; unsigned int index; if (mv) { for (index = 1; index <= me->totvert; index++, mv++) { - if (EDBM_backbuf_check(index)) { - if (!(mv->flag & ME_HIDE)) { - mv->flag = select ? (mv->flag | SELECT) : (mv->flag & ~SELECT); + if (!(mv->flag & ME_HIDE)) { + const bool is_select = mv->flag & SELECT; + const bool is_inside = EDBM_backbuf_check(index); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT); } } } @@ -216,15 +228,20 @@ static void edbm_backbuf_check_and_select_verts_obmode(Mesh *me, const bool sele } /* object mode, edbm_ prefix is confusing here, rename? */ -static void edbm_backbuf_check_and_select_tfaces(Mesh *me, const bool select) +static void edbm_backbuf_check_and_select_tfaces(Mesh *me, const eSelectOp sel_op) { MPoly *mpoly = me->mpoly; unsigned int index; if (mpoly) { for (index = 1; index <= me->totpoly; index++, mpoly++) { - if (EDBM_backbuf_check(index)) { - mpoly->flag = select ? (mpoly->flag | ME_FACE_SEL) : (mpoly->flag & ~ME_FACE_SEL); + if (!(mpoly->flag & ME_HIDE)) { + const bool is_select = mpoly->flag & ME_FACE_SEL; + const bool is_inside = EDBM_backbuf_check(index); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(mpoly->flag, sel_op_result, ME_FACE_SEL); + } } } } @@ -239,7 +256,7 @@ typedef struct LassoSelectUserData { rctf _rect_fl; const int (*mcords)[2]; int moves; - bool select; + eSelectOp sel_op; /* runtime */ int pass; @@ -250,7 +267,7 @@ typedef struct LassoSelectUserData { static void view3d_userdata_lassoselect_init( LassoSelectUserData *r_data, ViewContext *vc, const rcti *rect, const int (*mcords)[2], - const int moves, const bool select) + const int moves, const eSelectOp sel_op) { r_data->vc = vc; @@ -260,7 +277,7 @@ static void view3d_userdata_lassoselect_init( r_data->mcords = mcords; r_data->moves = moves; - r_data->select = select; + r_data->sel_op = sel_op; /* runtime */ r_data->pass = 0; @@ -362,17 +379,22 @@ static void do_lasso_select_pose__doSelectBone( /* if one of points selected, we skip the bone itself */ if ((is_point_done == true) || - ((is_point_done == false) && (points_proj_tot == 2) && - BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, INT_MAX))) + ((is_point_done == false) && (points_proj_tot == 2))) { - if (data->select) pchan->bone->flag |= BONE_SELECTED; - else pchan->bone->flag &= ~BONE_SELECTED; - data->is_changed = true; + const bool is_select = pchan->bone->flag & BONE_SELECTED; + const bool is_inside = BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, INT_MAX); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(pchan->bone->flag, sel_op_result, BONE_SELECTED); + data->is_changed = true; + } } data->is_changed |= is_point_done; } } -static void do_lasso_select_pose(ViewContext *vc, Object *ob, const int mcords[][2], short moves, const bool select) +static void do_lasso_select_pose( + ViewContext *vc, Object *ob, const int mcords[][2], short moves, + const eSelectOp sel_op) { ViewContext vc_tmp; LassoSelectUserData data; @@ -387,7 +409,7 @@ static void do_lasso_select_pose(ViewContext *vc, Object *ob, const int mcords[] BLI_lasso_boundbox(&rect, mcords, moves); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); @@ -417,13 +439,14 @@ static void object_deselect_all_visible(ViewLayer *view_layer) static void do_lasso_select_objects( ViewContext *vc, const int mcords[][2], const short moves, - const bool extend, const bool select) + const eSelectOp sel_op) { bool is_pose_mode = vc->obact ? (vc->obact->mode & OB_MODE_POSE) : false; Base *base; - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { object_deselect_all_visible(vc->view_layer); + } for (base = vc->view_layer->object_bases.first; base; base = base->next) { if (BASE_SELECTABLE(base)) { /* use this to avoid un-needed lasso lookups */ @@ -431,13 +454,15 @@ static void do_lasso_select_objects( (is_pose_mode == false) : true) && ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK) { - if (BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED)) { - - ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); + const bool is_select = base->flag & BASE_SELECTED; + const bool is_inside = BLI_lasso_is_point_inside(mcords, moves, base->sx, base->sy, IS_CLIPPED); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT); } } if (is_pose_mode && (base->object->mode & OB_MODE_POSE)) { - do_lasso_select_pose(vc, base->object, mcords, moves, select); + do_lasso_select_pose(vc, base->object, mcords, moves, sel_op); } } } @@ -446,54 +471,63 @@ static void do_lasso_select_objects( static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index)) { LassoSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) - { - BM_vert_select_set(data->vc->em->bm, eve, data->select); + const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT); + const bool is_inside = ( + BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_vert_select_set(data->vc->em->bm, eve, sel_op_result); } } -static void do_lasso_select_mesh__doSelectEdge( +static void do_lasso_select_mesh__doSelectEdge_pass0( void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) { LassoSelectUserData *data = userData; - - if (EDBM_backbuf_check(bm_solidoffs + index)) { - const int x0 = screen_co_a[0]; - const int y0 = screen_co_a[1]; - const int x1 = screen_co_b[0]; - const int y1 = screen_co_b[1]; - - if (data->pass == 0) { - if (edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) && - BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, IS_CLIPPED) && - BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, IS_CLIPPED)) - { - BM_edge_select_set(data->vc->em->bm, eed, data->select); - data->is_done = true; - } - } - else { - if (BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, IS_CLIPPED)) { - BM_edge_select_set(data->vc->em->bm, eed, data->select); - } - } + const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); + const bool is_inside = ( + EDBM_backbuf_check(bm_solidoffs + index) && + edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) && + BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), IS_CLIPPED) && + BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), IS_CLIPPED)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); + data->is_done = true; + } +} +static void do_lasso_select_mesh__doSelectEdge_pass1( + void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) +{ + LassoSelectUserData *data = userData; + const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); + const bool is_inside = ( + EDBM_backbuf_check(bm_solidoffs + index) && + BLI_lasso_is_edge_inside( + data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), IS_CLIPPED)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); } } + static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index)) { LassoSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) - { - BM_face_select_set(data->vc->em->bm, efa, data->select); + const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); + const bool is_inside = ( + BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside( + data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_face_select_set(data->vc->em->bm, efa, sel_op_result); } } static void do_lasso_select_mesh( ViewContext *vc, - const int mcords[][2], short moves, bool extend, bool select) + const int mcords[][2], short moves, const eSelectOp sel_op) { LassoSelectUserData data; ToolSettings *ts = vc->scene->toolsettings; @@ -505,10 +539,11 @@ static void do_lasso_select_mesh( BLI_lasso_boundbox(&rect, mcords, moves); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT); + } /* for non zbuf projections, don't change the GL state */ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); @@ -518,7 +553,7 @@ static void do_lasso_select_mesh( if (ts->selectmode & SCE_SELECT_VERTEX) { if (bbsel) { - edbm_backbuf_check_and_select_verts(vc->em, select); + edbm_backbuf_check_and_select_verts(vc->em, sel_op); } else { mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -526,18 +561,15 @@ static void do_lasso_select_mesh( } if (ts->selectmode & SCE_SELECT_EDGE) { /* Does both bbsel and non-bbsel versions (need screen cos for both) */ - data.pass = 0; - mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR); - + mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge_pass0, &data, V3D_PROJ_TEST_CLIP_NEAR); if (data.is_done == false) { - data.pass = 1; - mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR); + mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge_pass1, &data, V3D_PROJ_TEST_CLIP_NEAR); } } if (ts->selectmode & SCE_SELECT_FACE) { if (bbsel) { - edbm_backbuf_check_and_select_faces(vc->em, select); + edbm_backbuf_check_and_select_faces(vc->em, sel_op); } else { mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -548,46 +580,52 @@ static void do_lasso_select_mesh( EDBM_selectmode_flush(vc->em); } -static void do_lasso_select_curve__doSelect(void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2]) +static void do_lasso_select_curve__doSelect( + void *userData, Nurb *UNUSED(nu), BPoint *bp, BezTriple *bezt, int beztindex, const float screen_co[2]) { LassoSelectUserData *data = userData; Object *obedit = data->vc->obedit; Curve *cu = (Curve *)obedit->data; - if (BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) { - if (bp) { - bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); + const bool is_inside = BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED); + if (bp) { + const bool is_select = bp->f1 & SELECT; + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT); } - else { - if (cu->drawflag & CU_HIDE_HANDLES) { - /* can only be (beztindex == 0) here since handles are hidden */ - bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT); + } + else { + if (cu->drawflag & CU_HIDE_HANDLES) { + /* can only be (beztindex == 0) here since handles are hidden */ + const bool is_select = bezt->f2 & SELECT; + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT); } - else { - if (beztindex == 0) { - bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT); - } - else if (beztindex == 1) { - bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT); - } - else { - bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT); - } + bezt->f1 = bezt->f3 = bezt->f2; + } + else { + char *flag_p = (&bezt->f1) + beztindex; + const bool is_select = *flag_p & SELECT; + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT); } } } } -static void do_lasso_select_curve(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select) +static void do_lasso_select_curve(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; BLI_lasso_boundbox(&rect, mcords, moves); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); - if (extend == false && select) { + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { Curve *curve = (Curve *) vc->obedit->data; ED_curve_deselect_all(curve->editnurb); } @@ -600,24 +638,27 @@ static void do_lasso_select_curve(ViewContext *vc, const int mcords[][2], short static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const float screen_co[2]) { LassoSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) - { - bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); + const bool is_select = bp->f1 | SELECT; + const bool is_inside = ( + BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT); } } -static void do_lasso_select_lattice(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select) +static void do_lasso_select_lattice(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; BLI_lasso_boundbox(&rect, mcords, moves); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { ED_lattice_flags_set(vc->obedit, 0); + } ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ lattice_foreachScreenVert(vc, do_lasso_select_lattice__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -627,46 +668,53 @@ static void do_lasso_select_armature__doSelectBone(void *userData, struct EditBo { LassoSelectUserData *data = userData; bArmature *arm = data->vc->obedit->data; - - if (data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone)) { + if (EBONE_VISIBLE(arm, ebone)) { bool is_point_done = false; int points_proj_tot = 0; - const int x0 = screen_co_a[0]; - const int y0 = screen_co_a[1]; - const int x1 = screen_co_b[0]; - const int y1 = screen_co_b[1]; - /* project head location to screenspace */ - if (x0 != IS_CLIPPED) { + if (screen_co_a[0] != IS_CLIPPED) { points_proj_tot++; - if (BLI_rcti_isect_pt(data->rect, x0, y0) && - BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, INT_MAX)) - { - is_point_done = true; - if (data->select) ebone->flag |= BONE_ROOTSEL; - else ebone->flag &= ~BONE_ROOTSEL; + const bool is_select = ebone->flag & BONE_ROOTSEL; + const bool is_inside = ( + BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) && + BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) { + SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_ROOTSEL); + } } + is_point_done |= is_inside; } /* project tail location to screenspace */ - if (x1 != IS_CLIPPED) { + if (screen_co_b[0] != IS_CLIPPED) { points_proj_tot++; - if (BLI_rcti_isect_pt(data->rect, x1, y1) && - BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, INT_MAX)) - { - is_point_done = true; - if (data->select) ebone->flag |= BONE_TIPSEL; - else ebone->flag &= ~BONE_TIPSEL; + const bool is_select = ebone->flag & BONE_TIPSEL; + const bool is_inside = ( + BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) && + BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) { + SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, BONE_TIPSEL); + } } + is_point_done |= is_inside; } /* if one of points selected, we skip the bone itself */ - if ((is_point_done == false) && (points_proj_tot == 2) && - BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, INT_MAX)) - { - if (data->select) ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); - else ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + if ((is_point_done == false) && (points_proj_tot == 2)) { + const bool is_select = ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); + const bool is_inside = BLI_lasso_is_edge_inside( + data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + if (sel_op_result == 0 || EBONE_SELECTABLE(arm, ebone)) { + SET_FLAG_FROM_TEST(ebone->flag, sel_op_result, (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL)); + } + } data->is_changed = true; } @@ -674,19 +722,20 @@ static void do_lasso_select_armature__doSelectBone(void *userData, struct EditBo } } -static void do_lasso_select_armature(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select) +static void do_lasso_select_armature(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; BLI_lasso_boundbox(&rect, mcords, moves); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { ED_armature_edit_deselect_all_visible(vc->obedit); + } armature_foreachScreenBone(vc, do_lasso_select_armature__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -701,28 +750,30 @@ static void do_lasso_select_armature(ViewContext *vc, const int mcords[][2], sho static void do_lasso_select_mball__doSelectElem(void *userData, struct MetaElem *ml, const float screen_co[2]) { LassoSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX)) - { - if (data->select) ml->flag |= SELECT; - else ml->flag &= ~SELECT; + const bool is_select = ml->flag & SELECT; + const bool is_inside = ( + BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT); data->is_changed = true; } } -static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select) +static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op) { LassoSelectUserData data; rcti rect; MetaBall *mb = (MetaBall *)vc->obedit->data; - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { BKE_mball_deselect_all(mb); + } BLI_lasso_boundbox(&rect, mcords, moves); - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); @@ -732,14 +783,17 @@ static void do_lasso_select_meta(ViewContext *vc, const int mcords[][2], short m static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index)) { LassoSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && - BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) - { - SET_FLAG_FROM_TEST(mv->flag, data->select, SELECT); + const bool is_select = mv->flag & SELECT; + const bool is_inside = ( + BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && + BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT); + data->is_changed = true; } } -static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select) +static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op) { const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0; Object *ob = vc->obact; @@ -749,8 +803,9 @@ static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], sh if (me == NULL || me->totvert == 0) return; - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { paintvert_deselect_all_visible(ob, SEL_DESELECT, false); /* flush selection at the end */ + } BLI_lasso_boundbox(&rect, mcords, moves); @@ -759,14 +814,14 @@ static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], sh EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - edbm_backbuf_check_and_select_verts_obmode(me, select); + edbm_backbuf_check_and_select_verts_obmode(me, sel_op); EDBM_backbuf_free(); } else { LassoSelectUserData data; - view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, select); + view3d_userdata_lassoselect_init(&data, vc, &rect, mcords, moves, sel_op); ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); @@ -774,12 +829,12 @@ static void do_lasso_select_paintvert(ViewContext *vc, const int mcords[][2], sh } - if (select == false) { + if (SEL_OP_CAN_DESELECT(sel_op)) { BKE_mesh_mselect_validate(me); } paintvert_flush_flags(ob); } -static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], short moves, bool extend, bool select) +static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], short moves, const eSelectOp sel_op) { Object *ob = vc->obact; Mesh *me = ob->data; @@ -788,15 +843,16 @@ static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], sh if (me == NULL || me->totpoly == 0) return; - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { paintface_deselect_all_visible(ob, SEL_DESELECT, false); /* flush selection at the end */ + } bm_vertoffs = me->totpoly + 1; /* max index array */ BLI_lasso_boundbox(&rect, mcords, moves); EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); - edbm_backbuf_check_and_select_tfaces(me, select); + edbm_backbuf_check_and_select_tfaces(me, sel_op); EDBM_backbuf_free(); @@ -804,7 +860,7 @@ static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], sh } #if 0 -static void do_lasso_select_node(int mcords[][2], short moves, const bool select) +static void do_lasso_select_node(int mcords[][2], short moves, const eSelectOp sel_op) { SpaceNode *snode = sa->spacedata.first; @@ -821,13 +877,13 @@ static void do_lasso_select_node(int mcords[][2], short moves, const bool select node_centf[1] = BLI_RCT_CENTER_Y(&node->totr); ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent); - if (BLI_rcti_isect_pt_v(&rect, node_cent) && BLI_lasso_is_point_inside(mcords, moves, node_cent[0], node_cent[1])) { - if (select) { - node->flag |= SELECT; - } - else { - node->flag &= ~SELECT; - } + const bool is_select = node->flag & SELECT; + const bool is_inside = ( + BLI_rcti_isect_pt_v(&rect, node_cent) && + BLI_lasso_is_point_inside(mcords, moves, node_cent[0], node_cent[1])); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(node->flag, sel_op_result, SELECT); } } BIF_undo_push("Lasso select nodes"); @@ -837,25 +893,25 @@ static void do_lasso_select_node(int mcords[][2], short moves, const bool select static void view3d_lasso_select( bContext *C, ViewContext *vc, const int mcords[][2], short moves, - bool extend, bool select) + const eSelectOp sel_op) { Object *ob = CTX_data_active_object(C); if (vc->obedit == NULL) { /* Object Mode */ if (BKE_paint_select_face_test(ob)) { - do_lasso_select_paintface(vc, mcords, moves, extend, select); + do_lasso_select_paintface(vc, mcords, moves, sel_op); } else if (BKE_paint_select_vert_test(ob)) { - do_lasso_select_paintvert(vc, mcords, moves, extend, select); + do_lasso_select_paintvert(vc, mcords, moves, sel_op); } else if (ob && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) { /* pass */ } else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) { - PE_lasso_select(C, mcords, moves, extend, select); + PE_lasso_select(C, mcords, moves, sel_op); } else { - do_lasso_select_objects(vc, mcords, moves, extend, select); + do_lasso_select_objects(vc, mcords, moves, sel_op); DEG_id_tag_update(&vc->scene->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene); } @@ -867,20 +923,20 @@ static void view3d_lasso_select( switch (vc->obedit->type) { case OB_MESH: - do_lasso_select_mesh(vc, mcords, moves, extend, select); + do_lasso_select_mesh(vc, mcords, moves, sel_op); break; case OB_CURVE: case OB_SURF: - do_lasso_select_curve(vc, mcords, moves, extend, select); + do_lasso_select_curve(vc, mcords, moves, sel_op); break; case OB_LATTICE: - do_lasso_select_lattice(vc, mcords, moves, extend, select); + do_lasso_select_lattice(vc, mcords, moves, sel_op); break; case OB_ARMATURE: - do_lasso_select_armature(vc, mcords, moves, extend, select); + do_lasso_select_armature(vc, mcords, moves, sel_op); break; case OB_MBALL: - do_lasso_select_meta(vc, mcords, moves, extend, select); + do_lasso_select_meta(vc, mcords, moves, sel_op); break; default: assert(!"lasso select on incorrect object type"); @@ -904,15 +960,13 @@ static int view3d_lasso_select_exec(bContext *C, wmOperator *op) const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot); if (mcords) { - bool extend, select; view3d_operator_needs_opengl(C); /* setup view context for argument to callbacks */ ED_view3d_viewcontext_init(C, &vc); - extend = RNA_boolean_get(op->ptr, "extend"); - select = !RNA_boolean_get(op->ptr, "deselect"); - view3d_lasso_select(C, &vc, mcords, mcords_tot, extend, select); + eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + view3d_lasso_select(C, &vc, mcords, mcords_tot, sel_op); MEM_freeN((void *)mcords); @@ -937,7 +991,8 @@ void VIEW3D_OT_select_lasso(wmOperatorType *ot) ot->flag = OPTYPE_UNDO; /* properties */ - WM_operator_properties_gesture_lasso_select(ot); + WM_operator_properties_gesture_lasso(ot); + WM_operator_properties_select_operation(ot); } /* ************************** mouse select ************************* */ @@ -1716,17 +1771,16 @@ typedef struct BoxSelectUserData { const rcti *rect; const rctf *rect_fl; rctf _rect_fl; - bool select; + eSelectOp sel_op; /* runtime */ - int pass; bool is_done; bool is_changed; } BoxSelectUserData; static void view3d_userdata_boxselect_init( BoxSelectUserData *r_data, - ViewContext *vc, const rcti *rect, const bool select) + ViewContext *vc, const rcti *rect, const eSelectOp sel_op) { r_data->vc = vc; @@ -1734,10 +1788,9 @@ static void view3d_userdata_boxselect_init( r_data->rect_fl = &r_data->_rect_fl; BLI_rctf_rcti_copy(&r_data->_rect_fl, rect); - r_data->select = select; + r_data->sel_op = sel_op; /* runtime */ - r_data->pass = 0; r_data->is_done = false; r_data->is_changed = false; } @@ -1751,13 +1804,15 @@ bool edge_inside_circle(const float cent[2], float radius, const float screen_co static void do_paintvert_box_select__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index)) { BoxSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { - SET_FLAG_FROM_TEST(mv->flag, data->select, SELECT); + const bool is_select = mv->flag & SELECT; + const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(mv->flag, sel_op_result, SELECT); } } static int do_paintvert_box_select( - ViewContext *vc, rcti *rect, bool select, bool extend) + ViewContext *vc, rcti *rect, const eSelectOp sel_op) { const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0; Mesh *me; @@ -1776,8 +1831,9 @@ static int do_paintvert_box_select( return OPERATOR_CANCELLED; } - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, false); + } if (use_zbuf) { selar = MEM_callocN(me->totvert + 1, "selar"); @@ -1807,10 +1863,12 @@ static int do_paintvert_box_select( mvert = me->mvert; for (a = 1; a <= me->totvert; a++, mvert++) { - if (selar[a]) { - if ((mvert->flag & ME_HIDE) == 0) { - if (select) mvert->flag |= SELECT; - else mvert->flag &= ~SELECT; + if ((mvert->flag & ME_HIDE) == 0) { + const bool is_select = mvert->flag & SELECT; + const bool is_inside = (selar[a] != 0); + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(mvert->flag, sel_op_result, SELECT); } } } @@ -1825,14 +1883,14 @@ static int do_paintvert_box_select( else { BoxSelectUserData data; - view3d_userdata_boxselect_init(&data, vc, rect, select); + view3d_userdata_boxselect_init(&data, vc, rect, sel_op); ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d); meshobject_foreachScreenVert(vc, do_paintvert_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); } - if (select == false) { + if (SEL_OP_CAN_DESELECT(sel_op)) { BKE_mesh_mselect_validate(me); } paintvert_flush_flags(vc->obact); @@ -1847,36 +1905,41 @@ static void do_nurbs_box_select__doSelect( Object *obedit = data->vc->obedit; Curve *cu = (Curve *)obedit->data; - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { - if (bp) { - bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); + const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); + if (bp) { + const bool is_select = bp->f1 & SELECT; + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT); } - else { - if (cu->drawflag & CU_HIDE_HANDLES) { - /* can only be (beztindex == 0) here since handles are hidden */ - bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT); + } + else { + if (cu->drawflag & CU_HIDE_HANDLES) { + /* can only be (beztindex == 0) here since handles are hidden */ + const bool is_select = bezt->f2 & SELECT; + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(bezt->f2, sel_op_result, SELECT); } - else { - if (beztindex == 0) { - bezt->f1 = data->select ? (bezt->f1 | SELECT) : (bezt->f1 & ~SELECT); - } - else if (beztindex == 1) { - bezt->f2 = data->select ? (bezt->f2 | SELECT) : (bezt->f2 & ~SELECT); - } - else { - bezt->f3 = data->select ? (bezt->f3 | SELECT) : (bezt->f3 & ~SELECT); - } + bezt->f1 = bezt->f3 = bezt->f2; + } + else { + char *flag_p = (&bezt->f1) + beztindex; + const bool is_select = *flag_p & SELECT; + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT); } } } } -static int do_nurbs_box_select(ViewContext *vc, rcti *rect, bool select, bool extend) +static int do_nurbs_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op) { BoxSelectUserData data; - view3d_userdata_boxselect_init(&data, vc, rect, select); + view3d_userdata_boxselect_init(&data, vc, rect, sel_op); - if (extend == false && select) { + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { Curve *curve = (Curve *) vc->obedit->data; ED_curve_deselect_all(curve->editnurb); } @@ -1891,19 +1954,22 @@ static int do_nurbs_box_select(ViewContext *vc, rcti *rect, bool select, bool ex static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, const float screen_co[2]) { BoxSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { - bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); + const bool is_select = bp->f1 & SELECT; + const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(bp->f1, sel_op_result, SELECT); } } -static int do_lattice_box_select(ViewContext *vc, rcti *rect, bool select, bool extend) +static int do_lattice_box_select(ViewContext *vc, rcti *rect, const eSelectOp sel_op) { BoxSelectUserData data; - view3d_userdata_boxselect_init(&data, vc, rect, select); + view3d_userdata_boxselect_init(&data, vc, rect, sel_op); - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { ED_lattice_flags_set(vc->obedit, 0); + } ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ lattice_foreachScreenVert(vc, do_lattice_box_select__doSelect, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -1914,49 +1980,62 @@ static int do_lattice_box_select(ViewContext *vc, rcti *rect, bool select, bool static void do_mesh_box_select__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index)) { BoxSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { - BM_vert_select_set(data->vc->em->bm, eve, data->select); + const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT); + const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_vert_select_set(data->vc->em->bm, eve, sel_op_result); } } -static void do_mesh_box_select__doSelectEdge( +static void do_mesh_box_select__doSelectEdge_pass0( void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) { BoxSelectUserData *data = userData; - - if (EDBM_backbuf_check(bm_solidoffs + index)) { - if (data->pass == 0) { - if (edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b)) { - BM_edge_select_set(data->vc->em->bm, eed, data->select); - data->is_done = true; - } - } - else { - if (edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b)) { - BM_edge_select_set(data->vc->em->bm, eed, data->select); - } - } + const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); + const bool is_inside = ( + EDBM_backbuf_check(bm_solidoffs + index) && + edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); + } + data->is_done = true; +} +static void do_mesh_box_select__doSelectEdge_pass1( + void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index) +{ + BoxSelectUserData *data = userData; + const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT); + const bool is_inside = ( + EDBM_backbuf_check(bm_solidoffs + index) && + edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b)); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_edge_select_set(data->vc->em->bm, eed, sel_op_result); } } static void do_mesh_box_select__doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index)) { BoxSelectUserData *data = userData; - - if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { - BM_face_select_set(data->vc->em->bm, efa, data->select); + const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT); + const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co); + const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside); + if (sel_op_result != -1) { + BM_face_select_set(data->vc->em->bm, efa, sel_op_result); } } static int do_mesh_box_select( - ViewContext *vc, rcti *rect, bool select, bool extend) + ViewContext *vc, rcti *rect, const eSelectOp sel_op) { BoxSelectUserData data; ToolSettings *ts = vc->scene->toolsettings; int bbsel; - view3d_userdata_boxselect_init(&data, vc, rect, select); + view3d_userdata_boxselect_init(&data, vc, rect, sel_op); - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT); + } /* for non zbuf projections, don't change the GL state */ ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); @@ -1966,7 +2045,7 @@ static int do_mesh_box_select( if (ts->selectmode & SCE_SELECT_VERTEX) { if (bbsel) { - edbm_backbuf_check_and_select_verts(vc->em, select); + edbm_backbuf_check_and_select_verts(vc->em, sel_op); } else { mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -1974,19 +2053,15 @@ static int do_mesh_box_select( } if (ts->selectmode & SCE_SELECT_EDGE) { /* Does both bbsel and non-bbsel versions (need screen cos for both) */ - - data.pass = 0; - mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR); - - if (data.is_done == 0) { - data.pass = 1; - mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR); + mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge_pass0, &data, V3D_PROJ_TEST_CLIP_NEAR); + if (data.is_done == false) { + mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge_pass1, &data, V3D_PROJ_TEST_CLIP_NEAR); } } if (ts->selectmode & SCE_SELECT_FACE) { if (bbsel) { - edbm_backbuf_check_and_select_faces(vc->em, select); + edbm_backbuf_check_and_select_faces(vc->em, sel_op); } else { mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -2002,7 +2077,7 @@ static int do_mesh_box_select( static int do_meta_box_select( ViewContext *vc, - const rcti *rect, bool select, bool extend) + const rcti *rect, const eSelectOp sel_op) { MetaBall *mb = (MetaBall *)vc->obedit->data; MetaElem *ml; @@ -2015,24 +2090,35 @@ static int do_meta_box_select( vc, buffer, MAXPICKBUF, rect, VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP); - if (extend == false && select) + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { BKE_mball_deselect_all(mb); + } for (ml = mb->editelems->first; ml; ml = ml->next) { + bool is_inside_1 = false; + bool is_inside_2 = false; for (a = 0; a < hits; a++) { if (ml->selcol1 == buffer[(4 * a) + 3]) { - ml->flag |= MB_SCALE_RAD; - if (select) ml->flag |= SELECT; - else ml->flag &= ~SELECT; + is_inside_1 = true; break; } if (ml->selcol2 == buffer[(4 * a) + 3]) { - ml->flag &= ~MB_SCALE_RAD; - if (select) ml->flag |= SELECT; - else ml->flag &= ~SELECT; + is_inside_2 = true; break; } } + if (is_inside_1) { + ml->flag |= MB_SCALE_RAD; + } + if (is_inside_2) { + ml->flag &= ~MB_SCALE_RAD; + } + const bool is_select = (ml->flag & SELECT); + const bool is_inside = is_inside_1 || is_inside_2; + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT); + } } return OPERATOR_FINISHED; @@ -2040,8 +2126,10 @@ static int do_meta_box_select( static int do_armature_box_select( ViewContext *vc, - const rcti *rect, bool select, bool extend) + const rcti *rect, const eSelectOp sel_op) { + /* TODO(campbell): Full support for seleciton operations for edit bones. */ + const bool select = sel_op == SEL_OP_ADD; int a; unsigned int buffer[MAXPICKBUF]; @@ -2063,7 +2151,7 @@ static int do_armature_box_select( } } - if (extend == false && select) { + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { ED_armature_edit_deselect_all_visible_multi(objects, objects_len); } @@ -2164,7 +2252,7 @@ static int opengl_bone_select_buffer_cmp(const void *sel_a_p, const void *sel_b_ } } -static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, bool select, bool extend) +static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, const eSelectOp sel_op) { unsigned int *vbuffer = NULL; /* selection buffer */ int bone_only; @@ -2176,13 +2264,13 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b else bone_only = 0; - if (extend == false && select) { + if (SEL_OP_USE_PRE_DESELECT(sel_op)) { if (bone_only) { FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, OB_MODE_POSE, ob_iter) { bArmature *arm = ob_iter->data; for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) { if (PBONE_VISIBLE(arm, pchan->bone)) { - if ((select == false) || ((pchan->bone->flag & BONE_UNSELECTABLE) == 0)) { + if ((pchan->bone->flag & BONE_UNSELECTABLE) == 0) { pchan->bone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); } } @@ -2212,7 +2300,22 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b * keeping the same color until we have a hit. */ - if (hits > 0) { /* no need to loop if there's no hit */ + if (hits <= 0) { + if (SEL_OP_USE_OUTSIDE(sel_op)) { + for (Base *base = vc->view_layer->object_bases.first; base && hits; base = base->next) { + if (BASE_SELECTABLE(base)) { + const bool is_select = base->flag & BASE_SELECTED; + const bool is_inside = false; /* we know there are no hits. */ + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT); + } + } + } + } + } + else { + /* no need to loop if there's no hit */ /* The draw order doesn't always match the order we populate the engine, see: T51695. */ qsort(vbuffer, hits, sizeof(uint[4]), opengl_bone_select_buffer_cmp); @@ -2225,6 +2328,14 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b if ((base->object->select_color & 0x0000FFFF) != 0) { BLI_array_append(bases, base); } + else { + const bool is_select = base->flag & BASE_SELECTED; + const bool is_inside = false; /* we know there are no hits. */ + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT); + } + } } } @@ -2240,7 +2351,7 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b for (; col != col_end; col += 4) { /* should never fail */ if (bone != NULL) { - if (select) { + if (sel_op) { if ((bone->flag & BONE_UNSELECTABLE) == 0) { bone->flag |= BONE_SELECTED; } @@ -2256,7 +2367,12 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b changed = true; } else if (!bone_only) { - ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); + const bool is_select = base->flag & BASE_SELECTED; + const bool is_inside = true; + const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside); + if (sel_op_result != -1) { + ED_object_base_select(base, sel_op_result ? BA_SELECT : BA_DESELECT); + } } /* Select the next bone if we're not switching bases. */ @@ -2307,9 +2423,6 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op) { ViewContext vc; rcti rect; - bool extend; - bool select; - int ret = OPERATOR_CANCELLED; view3d_operator_needs_opengl(C); @@ -2317,8 +2430,7 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op) /* setup view context for argument to callbacks */ ED_view3d_viewcontext_init(C, &vc); - select = !RNA_boolean_get(op->ptr, "deselect"); - extend = RNA_boolean_get(op->ptr, "extend"); + eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); WM_operator_properties_border_to_rcti(op, &rect); if (vc.obedit) { @@ -2329,7 +2441,7 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op) switch (vc.obedit->type) { case OB_MESH: vc.em = BKE_editmesh_from_object(vc.obedit); - ret |= do_mesh_box_select(&vc, &rect, select, extend); + ret |= do_mesh_box_select(&vc, &rect, sel_op); if (ret & OPERATOR_FINISHED) { DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); @@ -2337,28 +2449,28 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op) break; case OB_CURVE: case OB_SURF: - ret |= do_nurbs_box_select(&vc, &rect, select, extend); + ret |= do_nurbs_box_select(&vc, &rect, sel_op); if (ret & OPERATOR_FINISHED) { DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); } break; case OB_MBALL: - ret |= do_meta_box_select(&vc, &rect, select, extend); + ret |= do_meta_box_select(&vc, &rect, sel_op); if (ret & OPERATOR_FINISHED) { DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); } break; case OB_ARMATURE: - ret |= do_armature_box_select(&vc, &rect, select, extend); + ret |= do_armature_box_select(&vc, &rect, sel_op); if (ret & OPERATOR_FINISHED) { DEG_id_tag_update(&vc.obedit->id, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit); } break; case OB_LATTICE: - ret |= do_lattice_box_select(&vc, &rect, select, extend); + ret |= do_lattice_box_select(&vc, &rect, sel_op); if (ret & OPERATOR_FINISHED) { DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); @@ -2373,19 +2485,20 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op) } else { /* no editmode, unified for bones and objects */ if (vc.obact && vc.obact->mode & OB_MODE_SCULPT) { - ret |= ED_sculpt_mask_box_select(C, &vc, &rect, select, extend); + /* XXX, this is not selection, could be it's own operator. */ + ret |= ED_sculpt_mask_box_select(C, &vc, &rect, sel_op == SEL_OP_ADD ? true : false); } else if (vc.obact && BKE_paint_select_face_test(vc.obact)) { - ret |= do_paintface_box_select(&vc, &rect, select, extend); + ret |= do_paintface_box_select(&vc, &rect, sel_op); } else if (vc.obact && BKE_paint_select_vert_test(vc.obact)) { - ret |= do_paintvert_box_select(&vc, &rect, select, extend); + ret |= do_paintvert_box_select(&vc, &rect, sel_op); } else if (vc.obact && vc.obact->mode & OB_MODE_PARTICLE_EDIT) { - ret |= PE_border_select(C, &rect, select, extend); + ret |= PE_border_select(C, &rect, sel_op); } else { /* object mode with none active */ - ret |= do_object_pose_box_select(C, &vc, &rect, select, extend); + ret |= do_object_pose_box_select(C, &vc, &rect, sel_op); } } @@ -2421,7 +2534,8 @@ void VIEW3D_OT_select_border(wmOperatorType *ot) ot->flag = OPTYPE_UNDO; /* rna */ - WM_operator_properties_gesture_border_select(ot); + WM_operator_properties_gesture_border(ot); + WM_operator_properties_select_operation(ot); } @@ -2648,7 +2762,7 @@ static void mesh_circle_select(ViewContext *vc, const bool select, const int mva if (ts->selectmode & SCE_SELECT_VERTEX) { if (bbsel) { - edbm_backbuf_check_and_select_verts(vc->em, select); + edbm_backbuf_check_and_select_verts(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); } else { mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -2657,7 +2771,7 @@ static void mesh_circle_select(ViewContext *vc, const bool select, const int mva if (ts->selectmode & SCE_SELECT_EDGE) { if (bbsel) { - edbm_backbuf_check_and_select_edges(vc->em, select); + edbm_backbuf_check_and_select_edges(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); } else { mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR); @@ -2666,7 +2780,7 @@ static void mesh_circle_select(ViewContext *vc, const bool select, const int mva if (ts->selectmode & SCE_SELECT_FACE) { if (bbsel) { - edbm_backbuf_check_and_select_faces(vc->em, select); + edbm_backbuf_check_and_select_faces(vc->em, select ? SEL_OP_ADD : SEL_OP_SUB); } else { mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); @@ -2687,7 +2801,7 @@ static void paint_facesel_circle_select(ViewContext *vc, const bool select, cons bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); if (bbsel) { - edbm_backbuf_check_and_select_tfaces(me, select); + edbm_backbuf_check_and_select_tfaces(me, select ? SEL_OP_ADD : SEL_OP_SUB); EDBM_backbuf_free(); paintface_flush_flags(ob, SELECT); } @@ -2714,7 +2828,7 @@ static void paint_vertsel_circle_select(ViewContext *vc, const bool select, cons bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f)); if (bbsel) { - edbm_backbuf_check_and_select_verts_obmode(me, select); + edbm_backbuf_check_and_select_verts_obmode(me, select ? SEL_OP_ADD : SEL_OP_SET); EDBM_backbuf_free(); } } diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index 97ea0da6007..3fd8656ad2c 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -43,6 +43,7 @@ set(SRC ed_transverts.c ed_util.c numinput.c + select_utils.c # general includes ../include/BIF_gl.h @@ -54,6 +55,7 @@ set(SRC ../include/ED_curve.h ../include/ED_datafiles.h ../include/ED_fileselect.h + ../include/ED_gizmo_library.h ../include/ED_gpencil.h ../include/ED_image.h ../include/ED_info.h @@ -63,7 +65,6 @@ set(SRC ../include/ED_lattice.h ../include/ED_logic.h ../include/ED_markers.h - ../include/ED_gizmo_library.h ../include/ED_mask.h ../include/ED_mball.h ../include/ED_mesh.h @@ -79,6 +80,7 @@ set(SRC ../include/ED_screen.h ../include/ED_screen_types.h ../include/ED_sculpt.h + ../include/ED_select_utils.h ../include/ED_sequencer.h ../include/ED_sound.h ../include/ED_space_api.h diff --git a/source/blender/editors/util/select_utils.c b/source/blender/editors/util/select_utils.c new file mode 100644 index 00000000000..39a49be3f67 --- /dev/null +++ b/source/blender/editors/util/select_utils.c @@ -0,0 +1,70 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file select_utils.c + * \ingroup editors + */ + +#include "BLI_utildefines.h" + +#include "ED_select_utils.h" + +/** 1: select, 0: deselect, -1: pass. */ +int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool is_inside) +{ + switch (sel_op) { + case SEL_OP_ADD: + return (!is_select && (is_inside)) ? 1 : -1; + case SEL_OP_SUB: + return (is_select && is_inside) ? 0 : -1; + case SEL_OP_SET: + return is_inside ? 1 : 0; + case SEL_OP_AND: + return (is_select && is_inside) ? -1 : (is_select ? 0 : -1); + case SEL_OP_XOR: + return (is_select && is_inside) ? 0 : ((!is_select && is_inside) ? 1 : -1); + } + BLI_assert(!"invalid sel_op"); + return -1; +} +/** + * Use when we've de-selected all items first (for modes that need it). + * + * \note In some cases changing selection needs to perform other checks, + * so it's more straightforward to deselect all, then select. + */ +int ED_select_op_action_deselected(const eSelectOp sel_op, const bool is_select, const bool is_inside) +{ + switch (sel_op) { + case SEL_OP_ADD: + return (!is_select && is_inside) ? 1 : -1; + case SEL_OP_SUB: + return (is_select && is_inside) ? 0 : -1; + case SEL_OP_SET: + /* Only difference w/ function above. */ + return is_inside ? 1 : -1; + case SEL_OP_AND: + return (is_select && is_inside) ? -1 : (is_select ? 0 : -1); + case SEL_OP_XOR: + return (is_select && is_inside) ? 0 : ((!is_select && is_inside) ? 1 : -1); + } + BLI_assert(!"invalid sel_op"); + return -1; +} diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 32bf32b03ab..3c5ba6a721f 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -76,6 +76,7 @@ #include "ED_uvedit.h" #include "ED_object.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_transform.h" #include "RNA_access.h" diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index b15ce2d11ad..45f6e188483 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -364,6 +364,7 @@ void WM_operator_properties_select_action(struct wmOperatorType *ot, int void WM_operator_properties_select_action_simple(struct wmOperatorType *ot, int default_action); void WM_operator_properties_select_random(struct wmOperatorType *ot); int WM_operator_properties_select_random_seed_increment_get(wmOperator *op); +void WM_operator_properties_select_operation(struct wmOperatorType *ot); struct CheckerIntervalParams { int nth; /* bypass when set to zero */ int skip; @@ -375,14 +376,6 @@ void WM_operator_properties_checker_interval_from_op( bool WM_operator_properties_checker_interval_test( const struct CheckerIntervalParams *op_params, int depth); - -/* MOVE THIS SOMEWHERE ELSE */ -#define SEL_TOGGLE 0 -#define SEL_SELECT 1 -#define SEL_DESELECT 2 -#define SEL_INVERT 3 - - /* flags for WM_operator_properties_filesel */ #define WM_FILESEL_RELPATH (1 << 0) @@ -391,7 +384,6 @@ bool WM_operator_properties_checker_interval_test( #define WM_FILESEL_FILEPATH (1 << 3) #define WM_FILESEL_FILES (1 << 4) - /* operator as a python command (resultuing string must be freed) */ char *WM_operator_pystring_ex(struct bContext *C, struct wmOperator *op, const bool all_args, const bool macro_args, diff --git a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c index 0b54f0cbec1..d0f6ab9f451 100644 --- a/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c +++ b/source/blender/windowmanager/gizmo/intern/wm_gizmo_map.c @@ -39,6 +39,7 @@ #include "BKE_global.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "ED_view3d.h" #include "GPU_glew.h" diff --git a/source/blender/windowmanager/intern/wm_gesture_ops.c b/source/blender/windowmanager/intern/wm_gesture_ops.c index 01184f47920..a4d811bf91b 100644 --- a/source/blender/windowmanager/intern/wm_gesture_ops.c +++ b/source/blender/windowmanager/intern/wm_gesture_ops.c @@ -49,6 +49,7 @@ #include "wm_event_system.h" #include "ED_screen.h" +#include "ED_select_utils.h" #include "RNA_access.h" #include "RNA_define.h" @@ -86,13 +87,22 @@ static void gesture_modal_state_to_operator(wmOperator *op, int modal_state) case GESTURE_MODAL_SELECT: case GESTURE_MODAL_DESELECT: if ((prop = RNA_struct_find_property(op->ptr, "deselect"))) { - RNA_property_boolean_set(op->ptr, prop, (modal_state == GESTURE_MODAL_DESELECT)); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_boolean_set(op->ptr, prop, (modal_state == GESTURE_MODAL_DESELECT)); + } + } + if ((prop = RNA_struct_find_property(op->ptr, "mode"))) { + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_enum_set(op->ptr, prop, (modal_state == GESTURE_MODAL_DESELECT) ? SEL_OP_SUB : SEL_OP_ADD); + } } break; case GESTURE_MODAL_IN: case GESTURE_MODAL_OUT: if ((prop = RNA_struct_find_property(op->ptr, "zoom_out"))) { - RNA_property_boolean_set(op->ptr, prop, (modal_state == GESTURE_MODAL_OUT)); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_boolean_set(op->ptr, prop, (modal_state == GESTURE_MODAL_OUT)); + } } break; } @@ -107,6 +117,11 @@ static int gesture_modal_state_from_operator(wmOperator *op) return RNA_property_boolean_get(op->ptr, prop) ? GESTURE_MODAL_DESELECT : GESTURE_MODAL_SELECT; } } + if ((prop = RNA_struct_find_property(op->ptr, "mode"))) { + if (RNA_property_is_set(op->ptr, prop)) { + return RNA_property_enum_get(op->ptr, prop) == SEL_OP_SUB ? GESTURE_MODAL_DESELECT : GESTURE_MODAL_SELECT; + } + } if ((prop = RNA_struct_find_property(op->ptr, "zoom_out"))) { if (RNA_property_is_set(op->ptr, prop)) { return RNA_property_boolean_get(op->ptr, prop) ? GESTURE_MODAL_OUT : GESTURE_MODAL_IN; diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index d4fb7279abc..ceb0fb75f78 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -39,6 +39,8 @@ #include "RNA_define.h" #include "RNA_enum_types.h" +#include "ED_select_utils.h" + #include "WM_api.h" #include "WM_types.h" @@ -250,6 +252,20 @@ void WM_operator_properties_gesture_border(wmOperatorType *ot) WM_operator_properties_gesture_border_ex(ot, false, false); } +void WM_operator_properties_select_operation(wmOperatorType *ot) +{ + static const EnumPropertyItem select_mode_items[] = { + {SEL_OP_ADD, "ADD", 0, "Add", ""}, + {SEL_OP_SUB, "SUB", 0, "Subtract", ""}, + {SEL_OP_SET, "SET", 0, "Set", ""}, + {SEL_OP_AND, "AND", 0, "And", ""}, + {SEL_OP_XOR, "XOR", 0, "Xor", ""}, + {0, NULL, 0, NULL, NULL} + }; + PropertyRNA *prop = RNA_def_enum(ot->srna, "mode", select_mode_items, SEL_OP_ADD, "Mode", ""); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + void WM_operator_properties_gesture_border_zoom(wmOperatorType *ot) { WM_operator_properties_border(ot); -- cgit v1.2.3