EditMesh: Support contracting the selection as well as extending
This allows for holding ctrl while switching from face->edge modes to select an edge-ring.
This commit is contained in:
parent
37dd7360d6
commit
caf8684b50
|
@ -1799,6 +1799,60 @@ bool BM_face_exists_overlap_subset(BMVert **varr, const int len)
|
|||
return is_overlap;
|
||||
}
|
||||
|
||||
bool BM_vert_is_all_edge_flag_test(const BMVert *v, const char hflag, const bool respect_hide)
|
||||
{
|
||||
if (v->e) {
|
||||
BMEdge *e_other;
|
||||
BMIter eiter;
|
||||
|
||||
BM_ITER_ELEM (e_other, &eiter, (BMVert *)v, BM_EDGES_OF_VERT) {
|
||||
if (!respect_hide || !BM_elem_flag_test(e_other, BM_ELEM_HIDDEN)) {
|
||||
if (!BM_elem_flag_test(e_other, hflag)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool BM_vert_is_all_face_flag_test(const BMVert *v, const char hflag, const bool respect_hide)
|
||||
{
|
||||
if (v->e) {
|
||||
BMEdge *f_other;
|
||||
BMIter fiter;
|
||||
|
||||
BM_ITER_ELEM (f_other, &fiter, (BMVert *)v, BM_FACES_OF_VERT) {
|
||||
if (!respect_hide || !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN)) {
|
||||
if (!BM_elem_flag_test(f_other, hflag)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool BM_edge_is_all_face_flag_test(const BMEdge *e, const char hflag, const bool respect_hide)
|
||||
{
|
||||
if (e->l) {
|
||||
BMLoop *l_iter, *l_first;
|
||||
|
||||
l_iter = l_first = e->l;
|
||||
do {
|
||||
if (!respect_hide || !BM_elem_flag_test(l_iter->f, BM_ELEM_HIDDEN)) {
|
||||
if (!BM_elem_flag_test(l_iter->f, hflag)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} while ((l_iter = l_iter->radial_next) != l_first);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* convenience functions for checking flags */
|
||||
bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag)
|
||||
|
|
|
@ -119,6 +119,10 @@ void BM_edge_ordered_verts(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2);
|
|||
void BM_edge_ordered_verts_ex(const BMEdge *edge, BMVert **r_v1, BMVert **r_v2,
|
||||
const BMLoop *edge_loop);
|
||||
|
||||
bool BM_vert_is_all_edge_flag_test(const BMVert *v, const char hflag, const bool respect_hide);
|
||||
bool BM_vert_is_all_face_flag_test(const BMVert *v, const char hflag, const bool respect_hide);
|
||||
bool BM_edge_is_all_face_flag_test(const BMEdge *e, const char hflag, const bool respect_hide);
|
||||
|
||||
bool BM_edge_is_any_vert_flag_test(const BMEdge *e, const char hflag);
|
||||
bool BM_face_is_any_vert_flag_test(const BMFace *f, const char hflag);
|
||||
bool BM_face_is_any_edge_flag_test(const BMFace *f, const char hflag);
|
||||
|
|
|
@ -1647,12 +1647,24 @@ void EDBM_selectmode_set(BMEditMesh *em)
|
|||
}
|
||||
|
||||
/**
|
||||
* Expand & Contract the Selection
|
||||
* (used when chaning modes and Ctrl key held)
|
||||
*
|
||||
* Flush the selection up:
|
||||
* - vert -> edge
|
||||
* - vert -> face
|
||||
* - edge -> face
|
||||
*
|
||||
* Flush the selection down:
|
||||
* - face -> edge
|
||||
* - face -> vert
|
||||
* - edge -> vert
|
||||
*/
|
||||
void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const short selectmode_new)
|
||||
{
|
||||
BMesh *bm = em->bm;
|
||||
|
||||
BMVert *eve;
|
||||
BMEdge *eed;
|
||||
BMFace *efa;
|
||||
BMIter iter;
|
||||
|
@ -1661,54 +1673,96 @@ void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const s
|
|||
|
||||
/* have to find out what the selectionmode was previously */
|
||||
if (selectmode_old == SCE_SELECT_VERTEX) {
|
||||
if (em->bm->totvertsel == 0) {
|
||||
if (bm->totvertsel == 0) {
|
||||
/* pass */
|
||||
}
|
||||
else if (selectmode_new == SCE_SELECT_EDGE) {
|
||||
/* flush up (vert -> edge) */
|
||||
|
||||
/* select all edges associated with every selected vert */
|
||||
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
|
||||
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
|
||||
BM_elem_flag_set(eed, BM_ELEM_TAG, BM_edge_is_any_vert_flag_test(eed, BM_ELEM_SELECT));
|
||||
}
|
||||
|
||||
BM_ITER_MESH (eed, &iter, em->bm, BM_EDGES_OF_MESH) {
|
||||
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
|
||||
if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
|
||||
BM_edge_select_set(em->bm, eed, true);
|
||||
BM_edge_select_set(bm, eed, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (selectmode_new == SCE_SELECT_FACE) {
|
||||
/* flush up (vert -> face) */
|
||||
|
||||
/* select all faces associated with every selected vert */
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BM_elem_flag_set(efa, BM_ELEM_TAG, BM_face_is_any_vert_flag_test(efa, BM_ELEM_SELECT));
|
||||
}
|
||||
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
||||
if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
|
||||
BM_face_select_set(em->bm, efa, true);
|
||||
BM_face_select_set(bm, efa, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (selectmode_old == SCE_SELECT_EDGE) {
|
||||
if (em->bm->totedgesel == 0) {
|
||||
if (bm->totedgesel == 0) {
|
||||
/* pass */
|
||||
}
|
||||
else if (selectmode_new == SCE_SELECT_FACE) {
|
||||
/* flush up (edge -> face) */
|
||||
|
||||
/* select all faces associated with every selected edge */
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
||||
BM_elem_flag_set(efa, BM_ELEM_TAG, BM_face_is_any_edge_flag_test(efa, BM_ELEM_SELECT));
|
||||
}
|
||||
|
||||
BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
|
||||
BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
|
||||
if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
|
||||
BM_face_select_set(em->bm, efa, true);
|
||||
BM_face_select_set(bm, efa, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (selectmode_new == SCE_SELECT_VERTEX) {
|
||||
/* flush down (edge -> vert) */
|
||||
|
||||
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
if (!BM_vert_is_all_edge_flag_test(eve, BM_ELEM_SELECT, true)) {
|
||||
BM_vert_select_set(bm, eve, false);
|
||||
}
|
||||
}
|
||||
/* deselect edges without both verts selected */
|
||||
BM_mesh_deselect_flush(bm);
|
||||
}
|
||||
}
|
||||
else if (selectmode_old == SCE_SELECT_FACE) {
|
||||
if (bm->totfacesel == 0) {
|
||||
/* pass */
|
||||
}
|
||||
else if (selectmode_new == SCE_SELECT_EDGE) {
|
||||
/* flush down (face -> edge) */
|
||||
|
||||
BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
|
||||
if (!BM_edge_is_all_face_flag_test(eed, BM_ELEM_SELECT, true)) {
|
||||
BM_edge_select_set(bm, eed, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (selectmode_new == SCE_SELECT_VERTEX) {
|
||||
/* flush down (face -> vert) */
|
||||
|
||||
BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
|
||||
if (!BM_vert_is_all_face_flag_test(eve, BM_ELEM_SELECT, true)) {
|
||||
BM_vert_select_set(bm, eve, false);
|
||||
}
|
||||
}
|
||||
/* deselect faces without verts selected */
|
||||
BM_mesh_deselect_flush(bm);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* user facing function, does notification and undo push */
|
||||
/* user facing function, does notification */
|
||||
bool EDBM_selectmode_toggle(bContext *C, const short selectmode_new,
|
||||
const int action, const bool use_extend, const bool use_expand)
|
||||
{
|
||||
|
@ -1755,22 +1809,24 @@ bool EDBM_selectmode_toggle(bContext *C, const short selectmode_new,
|
|||
break;
|
||||
}
|
||||
|
||||
if (use_extend == 0 || em->selectmode == 0) {
|
||||
if (use_expand) {
|
||||
const short selmode_max = highest_order_bit_s(ts->selectmode);
|
||||
EDBM_selectmode_convert(em, selmode_max, selectmode_new);
|
||||
}
|
||||
}
|
||||
|
||||
switch (selectmode_new) {
|
||||
case SCE_SELECT_VERTEX:
|
||||
if (use_extend == 0 || em->selectmode == 0)
|
||||
if (use_extend == 0 || em->selectmode == 0) {
|
||||
em->selectmode = SCE_SELECT_VERTEX;
|
||||
}
|
||||
ts->selectmode = em->selectmode;
|
||||
EDBM_selectmode_set(em);
|
||||
ret = true;
|
||||
break;
|
||||
case SCE_SELECT_EDGE:
|
||||
if (use_extend == 0 || em->selectmode == 0) {
|
||||
if (use_expand) {
|
||||
const short selmode_max = highest_order_bit_s(ts->selectmode);
|
||||
if (selmode_max == SCE_SELECT_VERTEX) {
|
||||
EDBM_selectmode_convert(em, selmode_max, SCE_SELECT_EDGE);
|
||||
}
|
||||
}
|
||||
em->selectmode = SCE_SELECT_EDGE;
|
||||
}
|
||||
ts->selectmode = em->selectmode;
|
||||
|
@ -1779,13 +1835,6 @@ bool EDBM_selectmode_toggle(bContext *C, const short selectmode_new,
|
|||
break;
|
||||
case SCE_SELECT_FACE:
|
||||
if (use_extend == 0 || em->selectmode == 0) {
|
||||
if (use_expand) {
|
||||
const short selmode_max = highest_order_bit_s(ts->selectmode);
|
||||
if (ELEM(selmode_max, SCE_SELECT_VERTEX, SCE_SELECT_EDGE)) {
|
||||
EDBM_selectmode_convert(em, selmode_max, SCE_SELECT_FACE);
|
||||
}
|
||||
}
|
||||
|
||||
em->selectmode = SCE_SELECT_FACE;
|
||||
}
|
||||
ts->selectmode = em->selectmode;
|
||||
|
|
Loading…
Reference in New Issue