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.
This commit is contained in:
Campbell Barton
2018-08-14 10:28:41 +10:00
parent d92d310b15
commit e88e80a6a0
55 changed files with 718 additions and 387 deletions

View File

@@ -373,18 +373,22 @@ class _defs_view3d_select:
@ToolDef.from_fn @ToolDef.from_fn
def border(): def border():
def draw_settings(context, layout, tool):
props = tool.operator_properties("view3d.select_border")
layout.prop(props, "mode", expand=True)
return dict( return dict(
text="Select Border", text="Select Border",
icon="ops.generic.select_border", icon="ops.generic.select_border",
widget=None, widget=None,
keymap=( keymap=(
("view3d.select_border", ("view3d.select_border",
dict(deselect=False), dict(mode='ADD'),
dict(type='EVT_TWEAK_A', value='ANY')), dict(type='EVT_TWEAK_A', value='ANY')),
("view3d.select_border", ("view3d.select_border",
dict(deselect=True), dict(mode='SUB'),
dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)), dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
), ),
draw_settings=draw_settings,
) )
@ToolDef.from_fn @ToolDef.from_fn
@@ -405,18 +409,22 @@ class _defs_view3d_select:
@ToolDef.from_fn @ToolDef.from_fn
def lasso(): def lasso():
def draw_settings(context, layout, tool):
props = tool.operator_properties("view3d.select_lasso")
layout.prop(props, "mode", expand=True)
return dict( return dict(
text="Select Lasso", text="Select Lasso",
icon="ops.generic.select_lasso", icon="ops.generic.select_lasso",
widget=None, widget=None,
keymap=( keymap=(
("view3d.select_lasso", ("view3d.select_lasso",
dict(deselect=False), dict(mode='ADD'),
dict(type='EVT_TWEAK_A', value='ANY')), dict(type='EVT_TWEAK_A', value='ANY')),
("view3d.select_lasso", ("view3d.select_lasso",
dict(deselect=True), dict(mode='SUB'),
dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)), dict(type='EVT_TWEAK_A', value='ANY', ctrl=True)),
), ),
draw_settings=draw_settings,
) )
# ----------------------------------------------------------------------------- # -----------------------------------------------------------------------------
# Object Modes (named based on context.mode) # Object Modes (named based on context.mode)

View File

@@ -67,6 +67,7 @@
#include "ED_keyframes_edit.h" // XXX move the select modes out of there! #include "ED_keyframes_edit.h" // XXX move the select modes out of there!
#include "ED_object.h" #include "ED_object.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "WM_api.h" #include "WM_api.h"
#include "WM_types.h" #include "WM_types.h"

View File

@@ -71,6 +71,7 @@
#include "ED_anim_api.h" #include "ED_anim_api.h"
#include "ED_markers.h" #include "ED_markers.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_util.h" #include "ED_util.h"
#include "ED_numinput.h" #include "ED_numinput.h"
#include "ED_object.h" #include "ED_object.h"

View File

@@ -35,6 +35,7 @@
#include "ED_armature.h" #include "ED_armature.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_transform.h" #include "ED_transform.h"
#include "armature_intern.h" #include "armature_intern.h"

View File

@@ -55,6 +55,7 @@
#include "ED_armature.h" #include "ED_armature.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_view3d.h" #include "ED_view3d.h"
#include "DEG_depsgraph.h" #include "DEG_depsgraph.h"

View File

@@ -60,6 +60,7 @@
#include "ED_mesh.h" #include "ED_mesh.h"
#include "ED_object.h" #include "ED_object.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_view3d.h" #include "ED_view3d.h"
#include "armature_intern.h" #include "armature_intern.h"

View File

@@ -44,6 +44,7 @@
#include "ED_curve.h" #include "ED_curve.h"
#include "ED_object.h" #include "ED_object.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_transform.h" #include "ED_transform.h"
#include "curve_intern.h" #include "curve_intern.h"

View File

@@ -49,6 +49,7 @@
#include "WM_types.h" #include "WM_types.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_types.h" #include "ED_types.h"
#include "ED_view3d.h" #include "ED_view3d.h"
#include "ED_curve.h" #include "ED_curve.h"

View File

@@ -50,6 +50,7 @@
#include "RNA_access.h" #include "RNA_access.h"
#include "ED_gpencil.h" #include "ED_gpencil.h"
#include "ED_select_utils.h"
#include "ED_object.h" #include "ED_object.h"
#include "ED_transform.h" #include "ED_transform.h"

View File

@@ -62,6 +62,7 @@
#include "UI_view2d.h" #include "UI_view2d.h"
#include "ED_gpencil.h" #include "ED_gpencil.h"
#include "ED_select_utils.h"
#include "DEG_depsgraph.h" #include "DEG_depsgraph.h"
#include "DEG_depsgraph_query.h" #include "DEG_depsgraph_query.h"

View File

@@ -204,7 +204,7 @@ void EMBM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct BMEd
/* editface.c */ /* editface.c */
void paintface_flush_flags(struct Object *ob, short flag); 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); 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_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); 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]); bool paintface_minmax(struct Object *ob, float r_min[3], float r_max[3]);

View File

@@ -62,9 +62,9 @@ void PE_update_object(
/* selection tools */ /* selection tools */
int PE_mouse_particles(struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); 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_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); void PE_deselect_all_visible(struct PTCacheEdit *edit);
/* particle_edit_undo.c */ /* particle_edit_undo.c */

View File

@@ -43,7 +43,7 @@ struct ListBase;
/* sculpt.c */ /* sculpt.c */
void ED_operatortypes_sculpt(void); void ED_operatortypes_sculpt(void);
void ED_sculpt_redraw_planes_get(float planes[4][4], struct ARegion *ar, struct Object *ob); 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 */ /* sculpt_undo.c */
void ED_sculpt_undosys_type(struct UndoType *ut); void ED_sculpt_undosys_type(struct UndoType *ut);

View File

@@ -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__ */

View File

@@ -53,6 +53,7 @@
#include "BKE_layer.h" #include "BKE_layer.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_lattice.h" #include "ED_lattice.h"
#include "ED_view3d.h" #include "ED_view3d.h"

View File

@@ -36,6 +36,7 @@
#include "WM_types.h" #include "WM_types.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_object.h" #include "ED_object.h"
#include "ED_lattice.h" #include "ED_lattice.h"

View File

@@ -45,6 +45,7 @@
#include "WM_api.h" #include "WM_api.h"
#include "WM_types.h" #include "WM_types.h"
#include "ED_select_utils.h"
#include "ED_mask.h" /* own include */ #include "ED_mask.h" /* own include */
#include "ED_screen.h" #include "ED_screen.h"

View File

@@ -42,6 +42,7 @@
#include "WM_types.h" #include "WM_types.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_mask.h" /* own include */ #include "ED_mask.h" /* own include */
#include "ED_image.h" #include "ED_image.h"
#include "ED_object.h" /* ED_keymap_proportional_maskmode only */ #include "ED_object.h" /* ED_keymap_proportional_maskmode only */

View File

@@ -52,6 +52,7 @@
#include "ED_keyframing.h" #include "ED_keyframing.h"
#include "ED_mask.h" #include "ED_mask.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "RNA_access.h" #include "RNA_access.h"
#include "RNA_define.h" #include "RNA_define.h"

View File

@@ -45,6 +45,7 @@
#include "WM_types.h" #include "WM_types.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_mask.h" /* own include */ #include "ED_mask.h" /* own include */
#include "RNA_access.h" #include "RNA_access.h"

View File

@@ -46,6 +46,7 @@
#include "ED_mesh.h" #include "ED_mesh.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_view3d.h" #include "ED_view3d.h"
#include "WM_api.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; 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; Object *ob = vc->obact;
Mesh *me; 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"); 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); 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; mpoly = me->mpoly;
for (a = 1; a <= me->totpoly; a++, mpoly++) { for (a = 1; a <= me->totpoly; a++, mpoly++) {
if (selar[a]) { if ((mpoly->flag & ME_HIDE) == 0) {
if (mpoly->flag & ME_HIDE) { const bool is_select = mpoly->flag & ME_FACE_SEL;
/* pass */ const bool is_inside = (selar[a] != 0);
} const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
else { if (sel_op_result != -1) {
if (select) mpoly->flag |= ME_FACE_SEL; SET_FLAG_FROM_TEST(mpoly->flag, sel_op_result, ME_FACE_SEL);
else mpoly->flag &= ~ME_FACE_SEL;
} }
} }
} }

View File

@@ -59,6 +59,7 @@
#include "ED_mesh.h" #include "ED_mesh.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_view3d.h" #include "ED_view3d.h"
#include "DNA_mesh_types.h" #include "DNA_mesh_types.h"

View File

@@ -40,6 +40,7 @@
#include "ED_object.h" #include "ED_object.h"
#include "ED_mesh.h" #include "ED_mesh.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "mesh_intern.h" /* own include */ #include "mesh_intern.h" /* own include */

View File

@@ -55,6 +55,7 @@
#include "ED_mball.h" #include "ED_mball.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_view3d.h" #include "ED_view3d.h"
#include "WM_api.h" #include "WM_api.h"

View File

@@ -37,6 +37,7 @@
#include "ED_mball.h" #include "ED_mball.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_object.h" #include "ED_object.h"
#include "mball_intern.h" #include "mball_intern.h"

View File

@@ -46,6 +46,7 @@
#include "WM_types.h" #include "WM_types.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_object.h" #include "ED_object.h"
#include "DEG_depsgraph.h" #include "DEG_depsgraph.h"

View File

@@ -72,6 +72,7 @@
#include "ED_object.h" #include "ED_object.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_keyframing.h" #include "ED_keyframing.h"
#include "UI_interface.h" #include "UI_interface.h"

View File

@@ -75,6 +75,7 @@
#include "ED_mesh.h" #include "ED_mesh.h"
#include "ED_particle.h" #include "ED_particle.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_view3d.h" #include "ED_view3d.h"
#include "GPU_immediate.h" #include "GPU_immediate.h"
@@ -418,6 +419,7 @@ typedef struct PEData {
float dist; float dist;
float dval; float dval;
int select; int select;
eSelectOp sel_op;
float *dvec; float *dvec;
float combfac; float combfac;
@@ -610,10 +612,15 @@ static bool point_is_selected(PTCacheEditPoint *point)
/*************************** iterators *******************************/ /*************************** iterators *******************************/
typedef void (*ForPointFunc)(PEData *data, int point_index); 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); 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); ParticleEditSettings *pset = PE_settings(data->scene);
PTCacheEdit *edit = data->edit; PTCacheEdit *edit = data->edit;
@@ -634,34 +641,45 @@ static void for_mouse_hit_keys(PEData *data, ForKeyFunc func, bool nearest)
/* only do end keys */ /* only do end keys */
key = point->keys + point->totkey - 1; key = point->keys + point->totkey - 1;
if (nearest) { if (flag & PSEL_NEAREST) {
if (key_inside_circle(data, dist, KEY_WCO, &dist)) { if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
nearest_point = p; nearest_point = p;
nearest_key = point->totkey - 1; nearest_key = point->totkey - 1;
} }
} }
else if (key_inside_test(data, KEY_WCO)) else {
func(data, p, point->totkey - 1); 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 { else {
/* do all keys */ /* do all keys */
LOOP_VISIBLE_KEYS { LOOP_VISIBLE_KEYS {
if (nearest) { if (flag & PSEL_NEAREST) {
if (key_inside_circle(data, dist, KEY_WCO, &dist)) { if (key_inside_circle(data, dist, KEY_WCO, &dist)) {
nearest_point = p; nearest_point = p;
nearest_key = k; nearest_key = k;
} }
} }
else if (key_inside_test(data, KEY_WCO)) else {
func(data, p, k); 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 */ /* do nearest only */
if (nearest && nearest_point > -1) if (flag & PSEL_NEAREST) {
func(data, nearest_point, nearest_key); if (nearest_point != -1) {
func(data, nearest_point, nearest_key, true);
}
}
} }
static void foreach_mouse_hit_point(PEData *data, ForPointFunc func, int selected) 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_VISIBLE_POINTS {
LOOP_SELECTED_KEYS { 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-----*/ /*-----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; PTCacheEdit *edit = data->edit;
PTCacheEditPoint *point = edit->points + point_index; 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; 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; PTCacheEdit *edit = data->edit;
PTCacheEditPoint *point = edit->points + point_index; 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; 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; PTCacheEdit *edit = data->edit;
PTCacheEditPoint *point = edit->points + point_index; 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; 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; PTCacheEdit *edit = data->edit;
PTCacheEditPoint *point = edit->points + point_index; 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; 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; PTCacheEdit *edit = data->edit;
PTCacheEditPoint *point = edit->points + point_index; 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(); data.rad = ED_view3d_select_dist_px();
/* 1 = nearest only */ /* 1 = nearest only */
if (extend) if (extend) {
for_mouse_hit_keys(&data, extend_key_select, true); for_mouse_hit_keys(&data, extend_key_select, PSEL_NEAREST);
else if (deselect) }
for_mouse_hit_keys(&data, deselect_key_select, true); else if (deselect) {
else for_mouse_hit_keys(&data, deselect_key_select, PSEL_NEAREST);
for_mouse_hit_keys(&data, toggle_key_select, true); }
else {
for_mouse_hit_keys(&data, toggle_key_select, PSEL_NEAREST);
}
PE_update_selection(data.depsgraph, scene, ob, 1); PE_update_selection(data.depsgraph, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob); 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.rad = 75.0f;
data.select = !RNA_boolean_get(op->ptr, "deselect"); 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); PE_update_selection(data.depsgraph, data.scene, data.ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, data.ob); 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); Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(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)) if (!PE_start_edit(edit))
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
if (extend == 0 && select) if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
PE_deselect_all_visible(edit); PE_deselect_all_visible(edit);
}
PE_set_view3d_data(C, &data); PE_set_view3d_data(C, &data);
data.rect = rect; 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); PE_update_selection(data.depsgraph, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob); 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.rad = rad;
data.select = selecting; 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); PE_update_selection(data.depsgraph, scene, ob, 1);
WM_event_add_notifier(C, NC_OBJECT | ND_PARTICLE | NA_SELECTED, ob); 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 ************************/ /************************ 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); Scene *scene = CTX_data_scene(C);
Object *ob = CTX_data_active_object(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)) if (!PE_start_edit(edit))
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
if (extend == 0 && select) if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
PE_deselect_all_visible(edit); PE_deselect_all_visible(edit);
}
/* only for depths */ /* only for depths */
PE_set_view3d_data(C, &data); 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 { LOOP_KEYS {
copy_v3_v3(co, key->co); copy_v3_v3(co, key->co);
mul_m4_v3(mat, 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) && const bool is_select = key->flag & PEK_SELECT;
BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) && const bool is_inside = (
key_test_depth(&data, co, screen_co)) (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) &&
if (select) { key_test_depth(&data, co, screen_co));
if (!(key->flag & PEK_SELECT)) { const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
key->flag |= PEK_SELECT; if (sel_op_result != -1) {
point->flag |= PEP_EDIT_RECALC; SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT);
} point->flag |= PEP_EDIT_RECALC;
}
else {
if (key->flag & PEK_SELECT) {
key->flag &= ~PEK_SELECT;
point->flag |= PEP_EDIT_RECALC;
}
}
} }
} }
} }
else if (pset->selectmode == SCE_SELECT_END) { else if (pset->selectmode == SCE_SELECT_END) {
if (point->totkey) { if (point->totkey) {
key = point->keys + point->totkey - 1; key = point->keys + point->totkey - 1;
copy_v3_v3(co, key->co); copy_v3_v3(co, key->co);
mul_m4_v3(mat, 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) && const bool is_select = key->flag & PEK_SELECT;
BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], IS_CLIPPED) && const bool is_inside = (
key_test_depth(&data, co, screen_co)) (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) &&
if (select) { key_test_depth(&data, co, screen_co));
if (!(key->flag & PEK_SELECT)) { const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
key->flag |= PEK_SELECT; if (sel_op_result != -1) {
point->flag |= PEP_EDIT_RECALC; SET_FLAG_FROM_TEST(key->flag, sel_op_result, PEK_SELECT);
} point->flag |= PEP_EDIT_RECALC;
}
else {
if (key->flag & PEK_SELECT) {
key->flag &= ~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; 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; PTCacheEdit *edit = data->edit;

View File

@@ -34,6 +34,7 @@
#include "WM_api.h" #include "WM_api.h"
#include "WM_types.h" #include "WM_types.h"
#include "ED_select_utils.h"
#include "ED_physics.h" #include "ED_physics.h"
#include "ED_object.h" #include "ED_object.h"

View File

@@ -258,7 +258,7 @@ static void mask_box_select_task_cb(
} BKE_pbvh_vertex_iter_end; } 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); Depsgraph *depsgraph = CTX_data_depsgraph(C);
Sculpt *sd = vc->scene->toolsettings->sculpt; Sculpt *sd = vc->scene->toolsettings->sculpt;

View File

@@ -48,6 +48,7 @@
#include "ED_paint.h" #include "ED_paint.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_image.h" #include "ED_image.h"
#include "ED_gpencil.h" #include "ED_gpencil.h"
#include "UI_resources.h" #include "UI_resources.h"
@@ -1444,9 +1445,9 @@ void ED_keymap_paint(wmKeyConfig *keyconf)
RNA_enum_set(kmi->ptr, "action", SEL_INVERT); RNA_enum_set(kmi->ptr, "action", SEL_INVERT);
WM_keymap_add_item(keymap, "VIEW3D_OT_select_border", BKEY, KM_PRESS, 0, 0); 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); 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); 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_select_circle", CKEY, KM_PRESS, 0, 0);
/* Image/Texture Paint mode */ /* Image/Texture Paint mode */

View File

@@ -40,6 +40,7 @@
#include "ED_markers.h" #include "ED_markers.h"
#include "ED_transform.h" #include "ED_transform.h"
#include "ED_object.h" #include "ED_object.h"
#include "ED_select_utils.h"
#include "action_intern.h" #include "action_intern.h"

View File

@@ -62,6 +62,7 @@
#include "ED_keyframes_edit.h" #include "ED_keyframes_edit.h"
#include "ED_markers.h" #include "ED_markers.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "WM_api.h" #include "WM_api.h"
#include "WM_types.h" #include "WM_types.h"

View File

@@ -44,6 +44,7 @@
#include "WM_types.h" #include "WM_types.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_clip.h" #include "ED_clip.h"
#include "RNA_access.h" #include "RNA_access.h"

View File

@@ -55,6 +55,7 @@
#include "ED_mask.h" #include "ED_mask.h"
#include "ED_space_api.h" #include "ED_space_api.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_clip.h" #include "ED_clip.h"
#include "ED_transform.h" #include "ED_transform.h"
#include "ED_uvedit.h" /* just for ED_image_draw_cursor */ #include "ED_uvedit.h" /* just for ED_image_draw_cursor */

View File

@@ -46,6 +46,7 @@
#include "WM_types.h" #include "WM_types.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_clip.h" #include "ED_clip.h"
#include "RNA_access.h" #include "RNA_access.h"

View File

@@ -48,6 +48,7 @@
#include "ED_anim_api.h" #include "ED_anim_api.h"
#include "ED_markers.h" #include "ED_markers.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_transform.h" #include "ED_transform.h"
#include "ED_object.h" #include "ED_object.h"

View File

@@ -56,6 +56,7 @@
#include "ED_anim_api.h" #include "ED_anim_api.h"
#include "ED_keyframes_edit.h" #include "ED_keyframes_edit.h"
#include "ED_markers.h" #include "ED_markers.h"
#include "ED_select_utils.h"
#include "WM_api.h" #include "WM_api.h"
#include "WM_types.h" #include "WM_types.h"

View File

@@ -39,6 +39,7 @@
#include "ED_anim_api.h" #include "ED_anim_api.h"
#include "ED_markers.h" #include "ED_markers.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_transform.h" #include "ED_transform.h"
#include "WM_api.h" #include "WM_api.h"

View File

@@ -46,6 +46,7 @@
#include "ED_anim_api.h" #include "ED_anim_api.h"
#include "ED_keyframes_edit.h" #include "ED_keyframes_edit.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "RNA_access.h" #include "RNA_access.h"
#include "RNA_define.h" #include "RNA_define.h"

View File

@@ -37,6 +37,7 @@
#include "ED_node.h" /* own include */ #include "ED_node.h" /* own include */
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_transform.h" #include "ED_transform.h"
#include "RNA_access.h" #include "RNA_access.h"

View File

@@ -45,6 +45,7 @@
#include "ED_node.h" /* own include */ #include "ED_node.h" /* own include */
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "RNA_access.h" #include "RNA_access.h"
#include "RNA_define.h" #include "RNA_define.h"

View File

@@ -71,6 +71,7 @@
#include "ED_object.h" #include "ED_object.h"
#include "ED_outliner.h" #include "ED_outliner.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_keyframing.h" #include "ED_keyframing.h"
#include "ED_armature.h" #include "ED_armature.h"

View File

@@ -52,6 +52,7 @@
#include "WM_types.h" #include "WM_types.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "outliner_intern.h" #include "outliner_intern.h"

View File

@@ -39,6 +39,7 @@
#include "ED_sequencer.h" #include "ED_sequencer.h"
#include "ED_markers.h" #include "ED_markers.h"
#include "ED_transform.h" /* transform keymap */ #include "ED_transform.h" /* transform keymap */
#include "ED_select_utils.h"
#include "BKE_sequencer.h" #include "BKE_sequencer.h"

View File

@@ -50,6 +50,7 @@
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_sequencer.h" #include "ED_sequencer.h"
#include "ED_select_utils.h"
#include "UI_view2d.h" #include "UI_view2d.h"

View File

@@ -57,6 +57,7 @@
#include "WM_types.h" #include "WM_types.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_transform.h" #include "ED_transform.h"
#include "view3d_intern.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); 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); 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); 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_select_circle", CKEY, KM_PRESS, 0, 0);
WM_keymap_add_item(keymap, "VIEW3D_OT_clip_border", BKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "VIEW3D_OT_clip_border", BKEY, KM_PRESS, KM_ALT, 0);

View File

@@ -95,6 +95,7 @@
#include "ED_mesh.h" #include "ED_mesh.h"
#include "ED_object.h" #include "ED_object.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_sculpt.h" #include "ED_sculpt.h"
#include "ED_mball.h" #include "ED_mball.h"
#include "ED_gpencil.h" #include "ED_gpencil.h"
@@ -149,7 +150,7 @@ void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact)
/* local prototypes */ /* 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; BMVert *eve;
BMIter iter; 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) { BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
if (EDBM_backbuf_check(index)) { const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
BM_vert_select_set(em->bm, eve, 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++; 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; BMEdge *eed;
BMIter iter; 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) { BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) {
if (EDBM_backbuf_check(index)) { const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
BM_edge_select_set(em->bm, eed, 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++; 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; BMFace *efa;
BMIter iter; 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) { BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
if (EDBM_backbuf_check(index)) { const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
BM_face_select_set(em->bm, efa, 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++; index++;
} }
} }
/* object mode, edbm_ prefix is confusing here, rename? */ /* 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; MVert *mv = me->mvert;
unsigned int index; unsigned int index;
if (mv) { if (mv) {
for (index = 1; index <= me->totvert; index++, mv++) { for (index = 1; index <= me->totvert; index++, mv++) {
if (EDBM_backbuf_check(index)) { if (!(mv->flag & ME_HIDE)) {
if (!(mv->flag & ME_HIDE)) { const bool is_select = mv->flag & SELECT;
mv->flag = select ? (mv->flag | 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? */ /* 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; MPoly *mpoly = me->mpoly;
unsigned int index; unsigned int index;
if (mpoly) { if (mpoly) {
for (index = 1; index <= me->totpoly; index++, mpoly++) { for (index = 1; index <= me->totpoly; index++, mpoly++) {
if (EDBM_backbuf_check(index)) { if (!(mpoly->flag & ME_HIDE)) {
mpoly->flag = select ? (mpoly->flag | ME_FACE_SEL) : (mpoly->flag & ~ME_FACE_SEL); 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; rctf _rect_fl;
const int (*mcords)[2]; const int (*mcords)[2];
int moves; int moves;
bool select; eSelectOp sel_op;
/* runtime */ /* runtime */
int pass; int pass;
@@ -250,7 +267,7 @@ typedef struct LassoSelectUserData {
static void view3d_userdata_lassoselect_init( static void view3d_userdata_lassoselect_init(
LassoSelectUserData *r_data, LassoSelectUserData *r_data,
ViewContext *vc, const rcti *rect, const int (*mcords)[2], 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; r_data->vc = vc;
@@ -260,7 +277,7 @@ static void view3d_userdata_lassoselect_init(
r_data->mcords = mcords; r_data->mcords = mcords;
r_data->moves = moves; r_data->moves = moves;
r_data->select = select; r_data->sel_op = sel_op;
/* runtime */ /* runtime */
r_data->pass = 0; 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 one of points selected, we skip the bone itself */
if ((is_point_done == true) || if ((is_point_done == true) ||
((is_point_done == false) && (points_proj_tot == 2) && ((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) pchan->bone->flag |= BONE_SELECTED; const bool is_select = pchan->bone->flag & BONE_SELECTED;
else pchan->bone->flag &= ~BONE_SELECTED; const bool is_inside = BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, INT_MAX);
data->is_changed = true; 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; 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; ViewContext vc_tmp;
LassoSelectUserData data; 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); 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); 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( static void do_lasso_select_objects(
ViewContext *vc, const int mcords[][2], const short moves, 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; bool is_pose_mode = vc->obact ? (vc->obact->mode & OB_MODE_POSE) : false;
Base *base; Base *base;
if (extend == false && select) if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
object_deselect_all_visible(vc->view_layer); object_deselect_all_visible(vc->view_layer);
}
for (base = vc->view_layer->object_bases.first; base; base = base->next) { for (base = vc->view_layer->object_bases.first; base; base = base->next) {
if (BASE_SELECTABLE(base)) { /* use this to avoid un-needed lasso lookups */ 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) && (is_pose_mode == false) : true) &&
ED_view3d_project_base(vc->ar, base) == V3D_PROJ_RET_OK) 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)) { 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);
ED_object_base_select(base, select ? BA_SELECT : BA_DESELECT); 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)) { 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)) static void do_lasso_select_mesh__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index))
{ {
LassoSelectUserData *data = userData; LassoSelectUserData *data = userData;
const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && const bool is_inside = (
BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) 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 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) void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
{ {
LassoSelectUserData *data = userData; LassoSelectUserData *data = userData;
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
if (EDBM_backbuf_check(bm_solidoffs + index)) { const bool is_inside = (
const int x0 = screen_co_a[0]; EDBM_backbuf_check(bm_solidoffs + index) &&
const int y0 = screen_co_a[1]; edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) &&
const int x1 = screen_co_b[0]; BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), IS_CLIPPED) &&
const int y1 = screen_co_b[1]; 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 (data->pass == 0) { if (sel_op_result != -1) {
if (edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b) && BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, IS_CLIPPED) && data->is_done = true;
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);
}
}
} }
} }
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)) static void do_lasso_select_mesh__doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
{ {
LassoSelectUserData *data = userData; LassoSelectUserData *data = userData;
const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && const bool is_inside = (
BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) BLI_rctf_isect_pt_v(data->rect_fl, screen_co) &&
{ BLI_lasso_is_point_inside(
BM_face_select_set(data->vc->em->bm, efa, data->select); 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( static void do_lasso_select_mesh(
ViewContext *vc, ViewContext *vc,
const int mcords[][2], short moves, bool extend, bool select) const int mcords[][2], short moves, const eSelectOp sel_op)
{ {
LassoSelectUserData data; LassoSelectUserData data;
ToolSettings *ts = vc->scene->toolsettings; ToolSettings *ts = vc->scene->toolsettings;
@@ -505,10 +539,11 @@ static void do_lasso_select_mesh(
BLI_lasso_boundbox(&rect, mcords, moves); 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); EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT);
}
/* for non zbuf projections, don't change the GL state */ /* for non zbuf projections, don't change the GL state */
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); 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 (ts->selectmode & SCE_SELECT_VERTEX) {
if (bbsel) { if (bbsel) {
edbm_backbuf_check_and_select_verts(vc->em, select); edbm_backbuf_check_and_select_verts(vc->em, sel_op);
} }
else { else {
mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); 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) { if (ts->selectmode & SCE_SELECT_EDGE) {
/* Does both bbsel and non-bbsel versions (need screen cos for both) */ /* Does both bbsel and non-bbsel versions (need screen cos for both) */
data.pass = 0; mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge_pass0, &data, V3D_PROJ_TEST_CLIP_NEAR);
mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR);
if (data.is_done == false) { if (data.is_done == false) {
data.pass = 1; mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge_pass1, &data, V3D_PROJ_TEST_CLIP_NEAR);
mesh_foreachScreenEdge(vc, do_lasso_select_mesh__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR);
} }
} }
if (ts->selectmode & SCE_SELECT_FACE) { if (ts->selectmode & SCE_SELECT_FACE) {
if (bbsel) { if (bbsel) {
edbm_backbuf_check_and_select_faces(vc->em, select); edbm_backbuf_check_and_select_faces(vc->em, sel_op);
} }
else { else {
mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); 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); 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; LassoSelectUserData *data = userData;
Object *obedit = data->vc->obedit; Object *obedit = data->vc->obedit;
Curve *cu = (Curve *)obedit->data; Curve *cu = (Curve *)obedit->data;
if (BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) { const bool is_inside = BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED);
if (bp) { if (bp) {
bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); 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 */
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);
}
bezt->f1 = bezt->f3 = bezt->f2;
} }
else { else {
if (cu->drawflag & CU_HIDE_HANDLES) { char *flag_p = (&bezt->f1) + beztindex;
/* can only be (beztindex == 0) here since handles are hidden */ const bool is_select = *flag_p & SELECT;
bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | 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) {
else { SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT);
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);
}
} }
} }
} }
} }
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; LassoSelectUserData data;
rcti rect; rcti rect;
BLI_lasso_boundbox(&rect, mcords, moves); 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; Curve *curve = (Curve *) vc->obedit->data;
ED_curve_deselect_all(curve->editnurb); 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]) static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, const float screen_co[2])
{ {
LassoSelectUserData *data = userData; LassoSelectUserData *data = userData;
const bool is_select = bp->f1 | SELECT;
if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && const bool is_inside = (
BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) 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 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; LassoSelectUserData data;
rcti rect; rcti rect;
BLI_lasso_boundbox(&rect, mcords, moves); 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_lattice_flags_set(vc->obedit, 0);
}
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ 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); 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; LassoSelectUserData *data = userData;
bArmature *arm = data->vc->obedit->data; bArmature *arm = data->vc->obedit->data;
if (EBONE_VISIBLE(arm, ebone)) {
if (data->select ? EBONE_SELECTABLE(arm, ebone) : EBONE_VISIBLE(arm, ebone)) {
bool is_point_done = false; bool is_point_done = false;
int points_proj_tot = 0; 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 */ /* project head location to screenspace */
if (x0 != IS_CLIPPED) { if (screen_co_a[0] != IS_CLIPPED) {
points_proj_tot++; points_proj_tot++;
if (BLI_rcti_isect_pt(data->rect, x0, y0) && const bool is_select = ebone->flag & BONE_ROOTSEL;
BLI_lasso_is_point_inside(data->mcords, data->moves, x0, y0, INT_MAX)) const bool is_inside = (
{ BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_a)) &&
is_point_done = true; BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_a), INT_MAX));
if (data->select) ebone->flag |= BONE_ROOTSEL; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
else ebone->flag &= ~BONE_ROOTSEL; 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 */ /* project tail location to screenspace */
if (x1 != IS_CLIPPED) { if (screen_co_b[0] != IS_CLIPPED) {
points_proj_tot++; points_proj_tot++;
if (BLI_rcti_isect_pt(data->rect, x1, y1) && const bool is_select = ebone->flag & BONE_TIPSEL;
BLI_lasso_is_point_inside(data->mcords, data->moves, x1, y1, INT_MAX)) const bool is_inside = (
{ BLI_rcti_isect_pt(data->rect, UNPACK2(screen_co_b)) &&
is_point_done = true; BLI_lasso_is_point_inside(data->mcords, data->moves, UNPACK2(screen_co_b), INT_MAX));
if (data->select) ebone->flag |= BONE_TIPSEL; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
else ebone->flag &= ~BONE_TIPSEL; 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 one of points selected, we skip the bone itself */
if ((is_point_done == false) && (points_proj_tot == 2) && if ((is_point_done == false) && (points_proj_tot == 2)) {
BLI_lasso_is_edge_inside(data->mcords, data->moves, x0, y0, x1, y1, INT_MAX)) const bool is_select = ebone->flag & (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL);
{ const bool is_inside = BLI_lasso_is_edge_inside(
if (data->select) ebone->flag |= (BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); data->mcords, data->moves, UNPACK2(screen_co_a), UNPACK2(screen_co_b), INT_MAX);
else ebone->flag &= ~(BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL); 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; 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; LassoSelectUserData data;
rcti rect; rcti rect;
BLI_lasso_boundbox(&rect, mcords, moves); 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); 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); ED_armature_edit_deselect_all_visible(vc->obedit);
}
armature_foreachScreenBone(vc, do_lasso_select_armature__doSelectBone, &data, V3D_PROJ_TEST_CLIP_DEFAULT); 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]) static void do_lasso_select_mball__doSelectElem(void *userData, struct MetaElem *ml, const float screen_co[2])
{ {
LassoSelectUserData *data = userData; LassoSelectUserData *data = userData;
const bool is_select = ml->flag & SELECT;
if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && const bool is_inside = (
BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], INT_MAX)) 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; const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
else ml->flag &= ~SELECT; if (sel_op_result != -1) {
SET_FLAG_FROM_TEST(ml->flag, sel_op_result, SELECT);
data->is_changed = true; 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; LassoSelectUserData data;
rcti rect; rcti rect;
MetaBall *mb = (MetaBall *)vc->obedit->data; MetaBall *mb = (MetaBall *)vc->obedit->data;
if (extend == false && select) if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
BKE_mball_deselect_all(mb); BKE_mball_deselect_all(mb);
}
BLI_lasso_boundbox(&rect, mcords, moves); 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); 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)) static void do_lasso_select_meshobject__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
{ {
LassoSelectUserData *data = userData; LassoSelectUserData *data = userData;
const bool is_select = mv->flag & SELECT;
if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co) && const bool is_inside = (
BLI_lasso_is_point_inside(data->mcords, data->moves, screen_co[0], screen_co[1], IS_CLIPPED)) 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 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; const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
Object *ob = vc->obact; 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) if (me == NULL || me->totvert == 0)
return; 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 */ paintvert_deselect_all_visible(ob, SEL_DESELECT, false); /* flush selection at the end */
}
BLI_lasso_boundbox(&rect, mcords, moves); 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_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(); EDBM_backbuf_free();
} }
else { else {
LassoSelectUserData data; 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); 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); BKE_mesh_mselect_validate(me);
} }
paintvert_flush_flags(ob); 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; Object *ob = vc->obact;
Mesh *me = ob->data; 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) if (me == NULL || me->totpoly == 0)
return; 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 */ paintface_deselect_all_visible(ob, SEL_DESELECT, false); /* flush selection at the end */
}
bm_vertoffs = me->totpoly + 1; /* max index array */ bm_vertoffs = me->totpoly + 1; /* max index array */
BLI_lasso_boundbox(&rect, mcords, moves); BLI_lasso_boundbox(&rect, mcords, moves);
EDBM_backbuf_border_mask_init(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax); 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(); EDBM_backbuf_free();
@@ -804,7 +860,7 @@ static void do_lasso_select_paintface(ViewContext *vc, const int mcords[][2], sh
} }
#if 0 #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; 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); node_centf[1] = BLI_RCT_CENTER_Y(&node->totr);
ipoco_to_areaco_noclip(G.v2d, node_centf, node_cent); 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])) { const bool is_select = node->flag & SELECT;
if (select) { const bool is_inside = (
node->flag |= SELECT; BLI_rcti_isect_pt_v(&rect, node_cent) &&
} BLI_lasso_is_point_inside(mcords, moves, node_cent[0], node_cent[1]));
else { const int sel_op_result = ED_select_op_action_deselected(sel_op, is_select, is_inside);
node->flag &= ~SELECT; if (sel_op_result != -1) {
} SET_FLAG_FROM_TEST(node->flag, sel_op_result, SELECT);
} }
} }
BIF_undo_push("Lasso select nodes"); 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( static void view3d_lasso_select(
bContext *C, ViewContext *vc, bContext *C, ViewContext *vc,
const int mcords[][2], short moves, const int mcords[][2], short moves,
bool extend, bool select) const eSelectOp sel_op)
{ {
Object *ob = CTX_data_active_object(C); Object *ob = CTX_data_active_object(C);
if (vc->obedit == NULL) { /* Object Mode */ if (vc->obedit == NULL) { /* Object Mode */
if (BKE_paint_select_face_test(ob)) { 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)) { 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))) { else if (ob && (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) {
/* pass */ /* pass */
} }
else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) { 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 { 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); DEG_id_tag_update(&vc->scene->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc->scene); 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) { switch (vc->obedit->type) {
case OB_MESH: case OB_MESH:
do_lasso_select_mesh(vc, mcords, moves, extend, select); do_lasso_select_mesh(vc, mcords, moves, sel_op);
break; break;
case OB_CURVE: case OB_CURVE:
case OB_SURF: case OB_SURF:
do_lasso_select_curve(vc, mcords, moves, extend, select); do_lasso_select_curve(vc, mcords, moves, sel_op);
break; break;
case OB_LATTICE: case OB_LATTICE:
do_lasso_select_lattice(vc, mcords, moves, extend, select); do_lasso_select_lattice(vc, mcords, moves, sel_op);
break; break;
case OB_ARMATURE: case OB_ARMATURE:
do_lasso_select_armature(vc, mcords, moves, extend, select); do_lasso_select_armature(vc, mcords, moves, sel_op);
break; break;
case OB_MBALL: case OB_MBALL:
do_lasso_select_meta(vc, mcords, moves, extend, select); do_lasso_select_meta(vc, mcords, moves, sel_op);
break; break;
default: default:
assert(!"lasso select on incorrect object type"); 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); const int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
if (mcords) { if (mcords) {
bool extend, select;
view3d_operator_needs_opengl(C); view3d_operator_needs_opengl(C);
/* setup view context for argument to callbacks */ /* setup view context for argument to callbacks */
ED_view3d_viewcontext_init(C, &vc); ED_view3d_viewcontext_init(C, &vc);
extend = RNA_boolean_get(op->ptr, "extend"); eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
select = !RNA_boolean_get(op->ptr, "deselect"); view3d_lasso_select(C, &vc, mcords, mcords_tot, sel_op);
view3d_lasso_select(C, &vc, mcords, mcords_tot, extend, select);
MEM_freeN((void *)mcords); MEM_freeN((void *)mcords);
@@ -937,7 +991,8 @@ void VIEW3D_OT_select_lasso(wmOperatorType *ot)
ot->flag = OPTYPE_UNDO; ot->flag = OPTYPE_UNDO;
/* properties */ /* properties */
WM_operator_properties_gesture_lasso_select(ot); WM_operator_properties_gesture_lasso(ot);
WM_operator_properties_select_operation(ot);
} }
/* ************************** mouse select ************************* */ /* ************************** mouse select ************************* */
@@ -1716,17 +1771,16 @@ typedef struct BoxSelectUserData {
const rcti *rect; const rcti *rect;
const rctf *rect_fl; const rctf *rect_fl;
rctf _rect_fl; rctf _rect_fl;
bool select; eSelectOp sel_op;
/* runtime */ /* runtime */
int pass;
bool is_done; bool is_done;
bool is_changed; bool is_changed;
} BoxSelectUserData; } BoxSelectUserData;
static void view3d_userdata_boxselect_init( static void view3d_userdata_boxselect_init(
BoxSelectUserData *r_data, BoxSelectUserData *r_data,
ViewContext *vc, const rcti *rect, const bool select) ViewContext *vc, const rcti *rect, const eSelectOp sel_op)
{ {
r_data->vc = vc; r_data->vc = vc;
@@ -1734,10 +1788,9 @@ static void view3d_userdata_boxselect_init(
r_data->rect_fl = &r_data->_rect_fl; r_data->rect_fl = &r_data->_rect_fl;
BLI_rctf_rcti_copy(&r_data->_rect_fl, rect); BLI_rctf_rcti_copy(&r_data->_rect_fl, rect);
r_data->select = select; r_data->sel_op = sel_op;
/* runtime */ /* runtime */
r_data->pass = 0;
r_data->is_done = false; r_data->is_done = false;
r_data->is_changed = 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)) static void do_paintvert_box_select__doSelectVert(void *userData, MVert *mv, const float screen_co[2], int UNUSED(index))
{ {
BoxSelectUserData *data = userData; BoxSelectUserData *data = userData;
const bool is_select = mv->flag & SELECT;
if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
SET_FLAG_FROM_TEST(mv->flag, data->select, 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(mv->flag, sel_op_result, SELECT);
} }
} }
static int do_paintvert_box_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; const bool use_zbuf = (vc->v3d->flag & V3D_ZBUF_SELECT) != 0;
Mesh *me; Mesh *me;
@@ -1776,8 +1831,9 @@ static int do_paintvert_box_select(
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
} }
if (extend == false && select) if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, false); paintvert_deselect_all_visible(vc->obact, SEL_DESELECT, false);
}
if (use_zbuf) { if (use_zbuf) {
selar = MEM_callocN(me->totvert + 1, "selar"); selar = MEM_callocN(me->totvert + 1, "selar");
@@ -1807,10 +1863,12 @@ static int do_paintvert_box_select(
mvert = me->mvert; mvert = me->mvert;
for (a = 1; a <= me->totvert; a++, mvert++) { for (a = 1; a <= me->totvert; a++, mvert++) {
if (selar[a]) { if ((mvert->flag & ME_HIDE) == 0) {
if ((mvert->flag & ME_HIDE) == 0) { const bool is_select = mvert->flag & SELECT;
if (select) mvert->flag |= SELECT; const bool is_inside = (selar[a] != 0);
else mvert->flag &= ~SELECT; 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 { else {
BoxSelectUserData data; 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); ED_view3d_init_mats_rv3d(vc->obact, vc->rv3d);
meshobject_foreachScreenVert(vc, do_paintvert_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); 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); BKE_mesh_mselect_validate(me);
} }
paintvert_flush_flags(vc->obact); paintvert_flush_flags(vc->obact);
@@ -1847,36 +1905,41 @@ static void do_nurbs_box_select__doSelect(
Object *obedit = data->vc->obedit; Object *obedit = data->vc->obedit;
Curve *cu = (Curve *)obedit->data; Curve *cu = (Curve *)obedit->data;
if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
if (bp) { if (bp) {
bp->f1 = data->select ? (bp->f1 | SELECT) : (bp->f1 & ~SELECT); 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 */
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);
}
bezt->f1 = bezt->f3 = bezt->f2;
} }
else { else {
if (cu->drawflag & CU_HIDE_HANDLES) { char *flag_p = (&bezt->f1) + beztindex;
/* can only be (beztindex == 0) here since handles are hidden */ const bool is_select = *flag_p & SELECT;
bezt->f1 = bezt->f2 = bezt->f3 = data->select ? (bezt->f2 | 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) {
else { SET_FLAG_FROM_TEST(*flag_p, sel_op_result, SELECT);
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);
}
} }
} }
} }
} }
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; 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; Curve *curve = (Curve *) vc->obedit->data;
ED_curve_deselect_all(curve->editnurb); 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]) static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, const float screen_co[2])
{ {
BoxSelectUserData *data = userData; BoxSelectUserData *data = userData;
const bool is_select = bp->f1 & SELECT;
if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
bp->f1 = data->select ? (bp->f1 | 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);
} }
} }
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; 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_lattice_flags_set(vc->obedit, 0);
}
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */ 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); 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)) static void do_mesh_box_select__doSelectVert(void *userData, BMVert *eve, const float screen_co[2], int UNUSED(index))
{ {
BoxSelectUserData *data = userData; BoxSelectUserData *data = userData;
const bool is_select = BM_elem_flag_test(eve, BM_ELEM_SELECT);
if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
BM_vert_select_set(data->vc->em->bm, eve, data->select); 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) void *userData, BMEdge *eed, const float screen_co_a[2], const float screen_co_b[2], int index)
{ {
BoxSelectUserData *data = userData; BoxSelectUserData *data = userData;
const bool is_select = BM_elem_flag_test(eed, BM_ELEM_SELECT);
if (EDBM_backbuf_check(bm_solidoffs + index)) { const bool is_inside = (
if (data->pass == 0) { EDBM_backbuf_check(bm_solidoffs + index) &&
if (edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b)) { edge_fully_inside_rect(data->rect_fl, screen_co_a, screen_co_b));
BM_edge_select_set(data->vc->em->bm, eed, data->select); const int sel_op_result = ED_select_op_action_deselected(data->sel_op, is_select, is_inside);
data->is_done = true; if (sel_op_result != -1) {
} BM_edge_select_set(data->vc->em->bm, eed, sel_op_result);
} }
else { data->is_done = true;
if (edge_inside_rect(data->rect_fl, screen_co_a, screen_co_b)) { }
BM_edge_select_set(data->vc->em->bm, eed, data->select); 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)) static void do_mesh_box_select__doSelectFace(void *userData, BMFace *efa, const float screen_co[2], int UNUSED(index))
{ {
BoxSelectUserData *data = userData; BoxSelectUserData *data = userData;
const bool is_select = BM_elem_flag_test(efa, BM_ELEM_SELECT);
if (BLI_rctf_isect_pt_v(data->rect_fl, screen_co)) { const bool is_inside = BLI_rctf_isect_pt_v(data->rect_fl, screen_co);
BM_face_select_set(data->vc->em->bm, efa, data->select); 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( static int do_mesh_box_select(
ViewContext *vc, rcti *rect, bool select, bool extend) ViewContext *vc, rcti *rect, const eSelectOp sel_op)
{ {
BoxSelectUserData data; BoxSelectUserData data;
ToolSettings *ts = vc->scene->toolsettings; ToolSettings *ts = vc->scene->toolsettings;
int bbsel; 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); EDBM_flag_disable_all(vc->em, BM_ELEM_SELECT);
}
/* for non zbuf projections, don't change the GL state */ /* for non zbuf projections, don't change the GL state */
ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); 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 (ts->selectmode & SCE_SELECT_VERTEX) {
if (bbsel) { if (bbsel) {
edbm_backbuf_check_and_select_verts(vc->em, select); edbm_backbuf_check_and_select_verts(vc->em, sel_op);
} }
else { else {
mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); 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) { if (ts->selectmode & SCE_SELECT_EDGE) {
/* Does both bbsel and non-bbsel versions (need screen cos for both) */ /* Does both bbsel and non-bbsel versions (need screen cos for both) */
mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge_pass0, &data, V3D_PROJ_TEST_CLIP_NEAR);
data.pass = 0; if (data.is_done == false) {
mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR); mesh_foreachScreenEdge(vc, do_mesh_box_select__doSelectEdge_pass1, &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);
} }
} }
if (ts->selectmode & SCE_SELECT_FACE) { if (ts->selectmode & SCE_SELECT_FACE) {
if (bbsel) { if (bbsel) {
edbm_backbuf_check_and_select_faces(vc->em, select); edbm_backbuf_check_and_select_faces(vc->em, sel_op);
} }
else { else {
mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); 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( static int do_meta_box_select(
ViewContext *vc, ViewContext *vc,
const rcti *rect, bool select, bool extend) const rcti *rect, const eSelectOp sel_op)
{ {
MetaBall *mb = (MetaBall *)vc->obedit->data; MetaBall *mb = (MetaBall *)vc->obedit->data;
MetaElem *ml; MetaElem *ml;
@@ -2015,24 +2090,35 @@ static int do_meta_box_select(
vc, buffer, MAXPICKBUF, rect, vc, buffer, MAXPICKBUF, rect,
VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP); VIEW3D_SELECT_ALL, VIEW3D_SELECT_FILTER_NOP);
if (extend == false && select) if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
BKE_mball_deselect_all(mb); BKE_mball_deselect_all(mb);
}
for (ml = mb->editelems->first; ml; ml = ml->next) { 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++) { for (a = 0; a < hits; a++) {
if (ml->selcol1 == buffer[(4 * a) + 3]) { if (ml->selcol1 == buffer[(4 * a) + 3]) {
ml->flag |= MB_SCALE_RAD; is_inside_1 = true;
if (select) ml->flag |= SELECT;
else ml->flag &= ~SELECT;
break; break;
} }
if (ml->selcol2 == buffer[(4 * a) + 3]) { if (ml->selcol2 == buffer[(4 * a) + 3]) {
ml->flag &= ~MB_SCALE_RAD; is_inside_2 = true;
if (select) ml->flag |= SELECT;
else ml->flag &= ~SELECT;
break; 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; return OPERATOR_FINISHED;
@@ -2040,8 +2126,10 @@ static int do_meta_box_select(
static int do_armature_box_select( static int do_armature_box_select(
ViewContext *vc, 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; int a;
unsigned int buffer[MAXPICKBUF]; 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); 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 */ unsigned int *vbuffer = NULL; /* selection buffer */
int bone_only; int bone_only;
@@ -2176,13 +2264,13 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
else else
bone_only = 0; bone_only = 0;
if (extend == false && select) { if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
if (bone_only) { if (bone_only) {
FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, OB_MODE_POSE, ob_iter) { FOREACH_OBJECT_IN_MODE_BEGIN (vc->view_layer, OB_MODE_POSE, ob_iter) {
bArmature *arm = ob_iter->data; bArmature *arm = ob_iter->data;
for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) { for (bPoseChannel *pchan = ob_iter->pose->chanbase.first; pchan; pchan = pchan->next) {
if (PBONE_VISIBLE(arm, pchan->bone)) { 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); 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. * 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. */ /* 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); 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) { if ((base->object->select_color & 0x0000FFFF) != 0) {
BLI_array_append(bases, base); 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) { for (; col != col_end; col += 4) {
/* should never fail */ /* should never fail */
if (bone != NULL) { if (bone != NULL) {
if (select) { if (sel_op) {
if ((bone->flag & BONE_UNSELECTABLE) == 0) { if ((bone->flag & BONE_UNSELECTABLE) == 0) {
bone->flag |= BONE_SELECTED; bone->flag |= BONE_SELECTED;
} }
@@ -2256,7 +2367,12 @@ static int do_object_pose_box_select(bContext *C, ViewContext *vc, rcti *rect, b
changed = true; changed = true;
} }
else if (!bone_only) { 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. */ /* 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; ViewContext vc;
rcti rect; rcti rect;
bool extend;
bool select;
int ret = OPERATOR_CANCELLED; int ret = OPERATOR_CANCELLED;
view3d_operator_needs_opengl(C); 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 */ /* setup view context for argument to callbacks */
ED_view3d_viewcontext_init(C, &vc); ED_view3d_viewcontext_init(C, &vc);
select = !RNA_boolean_get(op->ptr, "deselect"); eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
extend = RNA_boolean_get(op->ptr, "extend");
WM_operator_properties_border_to_rcti(op, &rect); WM_operator_properties_border_to_rcti(op, &rect);
if (vc.obedit) { if (vc.obedit) {
@@ -2329,7 +2441,7 @@ static int view3d_borderselect_exec(bContext *C, wmOperator *op)
switch (vc.obedit->type) { switch (vc.obedit->type) {
case OB_MESH: case OB_MESH:
vc.em = BKE_editmesh_from_object(vc.obedit); 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) { if (ret & OPERATOR_FINISHED) {
DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE); DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); 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; break;
case OB_CURVE: case OB_CURVE:
case OB_SURF: 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) { if (ret & OPERATOR_FINISHED) {
DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE); DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
} }
break; break;
case OB_MBALL: 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) { if (ret & OPERATOR_FINISHED) {
DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE); DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
} }
break; break;
case OB_ARMATURE: 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) { if (ret & OPERATOR_FINISHED) {
DEG_id_tag_update(&vc.obedit->id, DEG_TAG_SELECT_UPDATE); DEG_id_tag_update(&vc.obedit->id, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit); WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, vc.obedit);
} }
break; break;
case OB_LATTICE: 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) { if (ret & OPERATOR_FINISHED) {
DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE); DEG_id_tag_update(vc.obedit->data, DEG_TAG_SELECT_UPDATE);
WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data); 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 */ else { /* no editmode, unified for bones and objects */
if (vc.obact && vc.obact->mode & OB_MODE_SCULPT) { 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)) { 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)) { 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) { 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 */ 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; ot->flag = OPTYPE_UNDO;
/* rna */ /* 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 (ts->selectmode & SCE_SELECT_VERTEX) {
if (bbsel) { 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 { else {
mesh_foreachScreenVert(vc, mesh_circle_doSelectVert, &data, V3D_PROJ_TEST_CLIP_DEFAULT); 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 (ts->selectmode & SCE_SELECT_EDGE) {
if (bbsel) { 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 { else {
mesh_foreachScreenEdge(vc, mesh_circle_doSelectEdge, &data, V3D_PROJ_TEST_CLIP_NEAR); 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 (ts->selectmode & SCE_SELECT_FACE) {
if (bbsel) { 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 { else {
mesh_foreachScreenFace(vc, mesh_circle_doSelectFace, &data, V3D_PROJ_TEST_CLIP_DEFAULT); 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)); bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f));
if (bbsel) { 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(); EDBM_backbuf_free();
paintface_flush_flags(ob, SELECT); 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)); bbsel = EDBM_backbuf_circle_init(vc, mval[0], mval[1], (short)(rad + 1.0f));
if (bbsel) { 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(); EDBM_backbuf_free();
} }
} }

View File

@@ -43,6 +43,7 @@ set(SRC
ed_transverts.c ed_transverts.c
ed_util.c ed_util.c
numinput.c numinput.c
select_utils.c
# general includes # general includes
../include/BIF_gl.h ../include/BIF_gl.h
@@ -54,6 +55,7 @@ set(SRC
../include/ED_curve.h ../include/ED_curve.h
../include/ED_datafiles.h ../include/ED_datafiles.h
../include/ED_fileselect.h ../include/ED_fileselect.h
../include/ED_gizmo_library.h
../include/ED_gpencil.h ../include/ED_gpencil.h
../include/ED_image.h ../include/ED_image.h
../include/ED_info.h ../include/ED_info.h
@@ -63,7 +65,6 @@ set(SRC
../include/ED_lattice.h ../include/ED_lattice.h
../include/ED_logic.h ../include/ED_logic.h
../include/ED_markers.h ../include/ED_markers.h
../include/ED_gizmo_library.h
../include/ED_mask.h ../include/ED_mask.h
../include/ED_mball.h ../include/ED_mball.h
../include/ED_mesh.h ../include/ED_mesh.h
@@ -79,6 +80,7 @@ set(SRC
../include/ED_screen.h ../include/ED_screen.h
../include/ED_screen_types.h ../include/ED_screen_types.h
../include/ED_sculpt.h ../include/ED_sculpt.h
../include/ED_select_utils.h
../include/ED_sequencer.h ../include/ED_sequencer.h
../include/ED_sound.h ../include/ED_sound.h
../include/ED_space_api.h ../include/ED_space_api.h

View File

@@ -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;
}

View File

@@ -76,6 +76,7 @@
#include "ED_uvedit.h" #include "ED_uvedit.h"
#include "ED_object.h" #include "ED_object.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_transform.h" #include "ED_transform.h"
#include "RNA_access.h" #include "RNA_access.h"

View File

@@ -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_action_simple(struct wmOperatorType *ot, int default_action);
void WM_operator_properties_select_random(struct wmOperatorType *ot); void WM_operator_properties_select_random(struct wmOperatorType *ot);
int WM_operator_properties_select_random_seed_increment_get(wmOperator *op); int WM_operator_properties_select_random_seed_increment_get(wmOperator *op);
void WM_operator_properties_select_operation(struct wmOperatorType *ot);
struct CheckerIntervalParams { struct CheckerIntervalParams {
int nth; /* bypass when set to zero */ int nth; /* bypass when set to zero */
int skip; int skip;
@@ -375,14 +376,6 @@ void WM_operator_properties_checker_interval_from_op(
bool WM_operator_properties_checker_interval_test( bool WM_operator_properties_checker_interval_test(
const struct CheckerIntervalParams *op_params, int depth); 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 */ /* flags for WM_operator_properties_filesel */
#define WM_FILESEL_RELPATH (1 << 0) #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_FILEPATH (1 << 3)
#define WM_FILESEL_FILES (1 << 4) #define WM_FILESEL_FILES (1 << 4)
/* operator as a python command (resultuing string must be freed) */ /* operator as a python command (resultuing string must be freed) */
char *WM_operator_pystring_ex(struct bContext *C, struct wmOperator *op, char *WM_operator_pystring_ex(struct bContext *C, struct wmOperator *op,
const bool all_args, const bool macro_args, const bool all_args, const bool macro_args,

View File

@@ -39,6 +39,7 @@
#include "BKE_global.h" #include "BKE_global.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "ED_view3d.h" #include "ED_view3d.h"
#include "GPU_glew.h" #include "GPU_glew.h"

View File

@@ -49,6 +49,7 @@
#include "wm_event_system.h" #include "wm_event_system.h"
#include "ED_screen.h" #include "ED_screen.h"
#include "ED_select_utils.h"
#include "RNA_access.h" #include "RNA_access.h"
#include "RNA_define.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_SELECT:
case GESTURE_MODAL_DESELECT: case GESTURE_MODAL_DESELECT:
if ((prop = RNA_struct_find_property(op->ptr, "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; break;
case GESTURE_MODAL_IN: case GESTURE_MODAL_IN:
case GESTURE_MODAL_OUT: case GESTURE_MODAL_OUT:
if ((prop = RNA_struct_find_property(op->ptr, "zoom_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; 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; 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 ((prop = RNA_struct_find_property(op->ptr, "zoom_out"))) {
if (RNA_property_is_set(op->ptr, prop)) { if (RNA_property_is_set(op->ptr, prop)) {
return RNA_property_boolean_get(op->ptr, prop) ? GESTURE_MODAL_OUT : GESTURE_MODAL_IN; return RNA_property_boolean_get(op->ptr, prop) ? GESTURE_MODAL_OUT : GESTURE_MODAL_IN;

View File

@@ -39,6 +39,8 @@
#include "RNA_define.h" #include "RNA_define.h"
#include "RNA_enum_types.h" #include "RNA_enum_types.h"
#include "ED_select_utils.h"
#include "WM_api.h" #include "WM_api.h"
#include "WM_types.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); 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) void WM_operator_properties_gesture_border_zoom(wmOperatorType *ot)
{ {
WM_operator_properties_border(ot); WM_operator_properties_border(ot);