fix [#33142] Ctrl LMB higher selection mode in edit mode sometimes selects extra...
authorCampbell Barton <ideasman42@gmail.com>
Sun, 11 Nov 2012 23:33:59 +0000 (23:33 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Sun, 11 Nov 2012 23:33:59 +0000 (23:33 +0000)
source/blender/blenlib/intern/math_base_inline.c
source/blender/bmesh/intern/bmesh_queries.c
source/blender/bmesh/intern/bmesh_queries.h
source/blender/editors/mesh/editmesh_select.c
source/blender/editors/space_view3d/view3d_header.c

index f27da759482719e4eb9c0eb55b9e37acbb99f5a1..8dccded64d103f33cc68e72c3efbd34296bb8485 100644 (file)
@@ -139,6 +139,25 @@ MINLINE int power_of_2_min_i(int n)
        return n;
 }
 
+MINLINE unsigned int highest_order_bit_i(unsigned int n)
+{
+       n |= (n >>  1);
+       n |= (n >>  2);
+       n |= (n >>  4);
+       n |= (n >>  8);
+       n |= (n >> 16);
+       return n - (n >> 1);
+}
+
+MINLINE unsigned short highest_order_bit_s(unsigned short n)
+{
+       n |= (n >>  1);
+       n |= (n >>  2);
+       n |= (n >>  4);
+       n |= (n >>  8);
+       return n - (n >> 1);
+}
+
 MINLINE float min_ff(float a, float b)
 {
        return (a < b) ? a : b;
index 1e1d7d1becb4efa70aa34c9c3b375fc5adca6032..b37a82c7228bd72528017cff6b689849f1117d36 100644 (file)
@@ -1419,3 +1419,38 @@ int BM_face_exists_multi_edge(BMEdge **earr, int len)
 
        return ok;
 }
+
+/* convenience functiosn for checking flags */
+int BM_edge_is_any_vert_flag_test(BMEdge *e, const char hflag)
+{
+       return (BM_elem_flag_test(e->v1, hflag) ||
+               BM_elem_flag_test(e->v2, hflag));
+}
+
+int BM_face_is_any_vert_flag_test(BMFace *f, const char hflag)
+{
+       BMLoop *l_iter;
+       BMLoop *l_first;
+
+       l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+       do {
+               if (BM_elem_flag_test(l_iter->v, hflag)) {
+                       return TRUE;
+               }
+       } while ((l_iter = l_iter->next) != l_first);
+       return FALSE;
+}
+
+int BM_face_is_any_edge_flag_test(BMFace *f, const char hflag)
+{
+       BMLoop *l_iter;
+       BMLoop *l_first;
+
+       l_iter = l_first = BM_FACE_FIRST_LOOP(f);
+       do {
+               if (BM_elem_flag_test(l_iter->e, hflag)) {
+                       return TRUE;
+               }
+       } while ((l_iter = l_iter->next) != l_first);
+       return FALSE;
+}
index 579a1397b0c57526bfe98bc1272567944a0c5728..7bb456df8e8a8c1cf50ae9f22438db3cac631d31 100644 (file)
@@ -100,4 +100,8 @@ void    BM_edge_ordered_verts(BMEdge *edge, BMVert **r_v1, BMVert **r_v2);
 void    BM_edge_ordered_verts_ex(BMEdge *edge, BMVert **r_v1, BMVert **r_v2,
                                  BMLoop *edge_loop);
 
+int BM_edge_is_any_vert_flag_test(BMEdge *e, const char hflag);
+int BM_face_is_any_vert_flag_test(BMFace *f, const char hflag);
+int BM_face_is_any_edge_flag_test(BMFace *f, const char hflag);
+
 #endif /* __BMESH_QUERIES_H__ */
index 92ad0742ec95a84c670ddcabf87ea22c8158a7f7..2acbbb6e006088d5d0d07d24f9635ad35aa5a0ca 100644 (file)
@@ -1881,50 +1881,45 @@ void EDBM_selectmode_convert(BMEditMesh *em, const short selectmode_old, const s
        BMFace *efa;
        BMIter iter;
 
+       /* first tag-to-select, then select --- this avoids a feedback loop */
+
        /* have to find out what the selectionmode was previously */
        if (selectmode_old == SCE_SELECT_VERTEX) {
                if (selectmode_new == SCE_SELECT_EDGE) {
-                       /* select all edges associated with every selected vertex */
-                       eed = BM_iter_new(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
-                       for (; eed; eed = BM_iter_step(&iter)) {
-                               if ((BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) ||
-                                    BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)))
-                               {
+                       /* select all edges associated with every selected vert */
+                       BM_ITER_MESH (eed, &iter, em->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) {
+                               if (BM_elem_flag_test(eed, BM_ELEM_TAG)) {
                                        BM_edge_select_set(em->bm, eed, TRUE);
                                }
                        }
                }
                else if (selectmode_new == SCE_SELECT_FACE) {
-                       BMIter liter;
-                       BMLoop *l;
-
-                       /* select all faces associated with every selected vertex */
-                       efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
-                       for (; efa; efa = BM_iter_step(&iter)) {
-                               l = BM_iter_new(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
-                               for (; l; l = BM_iter_step(&liter)) {
-                                       if (BM_elem_flag_test(l->v, BM_ELEM_SELECT)) {
-                                               BM_face_select_set(em->bm, efa, TRUE);
-                                               break;
-                                       }
+                       /* select all faces associated with every selected vert */
+                       BM_ITER_MESH (efa, &iter, em->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) {
+                               if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+                                       BM_face_select_set(em->bm, efa, TRUE);
                                }
                        }
                }
        }
        else if (selectmode_old == SCE_SELECT_EDGE) {
                if (selectmode_new == SCE_SELECT_FACE) {
-                       BMIter liter;
-                       BMLoop *l;
-
-                       /* select all faces associated with every selected vertex */
-                       efa = BM_iter_new(&iter, em->bm, BM_FACES_OF_MESH, NULL);
-                       for (; efa; efa = BM_iter_step(&iter)) {
-                               l = BM_iter_new(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
-                               for (; l; l = BM_iter_step(&liter)) {
-                                       if (BM_elem_flag_test(l->v, BM_ELEM_SELECT)) {
-                                               BM_face_select_set(em->bm, efa, TRUE);
-                                               break;
-                                       }
+                       /* select all faces associated with every selected edge */
+                       BM_ITER_MESH (efa, &iter, em->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) {
+                               if (BM_elem_flag_test(efa, BM_ELEM_TAG)) {
+                                       BM_face_select_set(em->bm, efa, TRUE);
                                }
                        }
                }
index d8fcc7e12e7654fdf3a6f37602328a1ddb9bb876..7acb371041ce85be1e908e23c7f7db1ee875ffd5 100644 (file)
@@ -319,7 +319,7 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
        View3D *v3d = sa->spacedata.first;
        Object *obedit = CTX_data_edit_object(C);
        BMEditMesh *em = NULL;
-       int ctrl = win->eventstate->ctrl, shift = win->eventstate->shift;
+       const int ctrl = win->eventstate->ctrl, shift = win->eventstate->shift;
        PointerRNA props_ptr;
        
        if (obedit && obedit->type == OB_MESH) {
@@ -348,8 +348,11 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
                case B_SEL_EDGE:
                        if (em) {
                                if (shift == 0 || em->selectmode == 0) {
-                                       if ((em->selectmode ^ SCE_SELECT_EDGE) == SCE_SELECT_VERTEX) {
-                                               if (ctrl) EDBM_selectmode_convert(em, SCE_SELECT_VERTEX, SCE_SELECT_EDGE);
+                                       if (ctrl) {
+                                               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;
                                }
@@ -362,11 +365,13 @@ static void do_view3d_header_buttons(bContext *C, void *UNUSED(arg), int event)
                case B_SEL_FACE:
                        if (em) {
                                if (shift == 0 || em->selectmode == 0) {
-                                       if (((ts->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_VERTEX) ||
-                                           ((ts->selectmode ^ SCE_SELECT_FACE) == SCE_SELECT_EDGE))
-                                       {
-                                               if (ctrl) EDBM_selectmode_convert(em, (ts->selectmode ^ SCE_SELECT_FACE), SCE_SELECT_FACE);
+                                       if (ctrl) {
+                                               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;
@@ -430,9 +435,15 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C)
 
                row = uiLayoutRow(layout, TRUE);
                block = uiLayoutGetBlock(row);
-               uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL, 0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0, "Vertex select - Shift-Click for multiple modes");
-               uiDefIconButBitS(block, TOG, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL, 0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0, "Edge select - Shift-Click for multiple modes");
-               uiDefIconButBitS(block, TOG, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL, 0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0, "Face select - Shift-Click for multiple modes");
+               uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL,
+                                0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0,
+                                "Vertex select - Shift-Click for multiple modes");
+               uiDefIconButBitS(block, TOG, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL,
+                                0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0,
+                                "Edge select - Shift-Click for multiple modes, Ctrl-Click expands selection");
+               uiDefIconButBitS(block, TOG, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL,
+                                0, 0, UI_UNIT_X, UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0,
+                                "Face select - Shift-Click for multiple modes, Ctrl-Click expands selection");
        }
 }