2.5: warning fixes
[blender.git] / source / blender / editors / mesh / editmesh_mods.c
index 375ebde5f52787085ea664fb201b59c6cc6e92af..44f63427e5f250f37f6a9eab02d9f0ad2ab91df2 100644 (file)
@@ -67,6 +67,7 @@ editmesh_mods.c, UI level access, no geometry changes
 #include "BKE_material.h"
 #include "BKE_texture.h"
 #include "BKE_utildefines.h"
+#include "BKE_report.h"
 
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
@@ -79,7 +80,6 @@ editmesh_mods.c, UI level access, no geometry changes
 #include "RNA_access.h"
 #include "RNA_define.h"
 
-#include "ED_multires.h"
 #include "ED_mesh.h"
 #include "ED_screen.h"
 #include "ED_view3d.h"
@@ -91,9 +91,8 @@ editmesh_mods.c, UI level access, no geometry changes
 
 #include "BLO_sys_types.h" // for intptr_t support
 
-static void BIF_undo_push() {}
-static void waitcursor() {}
-static void error() {}
+/* XXX */
+static void waitcursor(int val) {}
 static int pupmenu() {return 0;}
 
 /* ****************************** MIRROR **************** */
@@ -125,7 +124,7 @@ void EM_automerge(int update)
 //       ) {
 //             len = removedoublesflag(1, 1, scene->toolsettings->doublimit);
 //             if (len) {
-//                     G.totvert -= len; /* saves doing a countall */
+//                     em->totvert -= len; /* saves doing a countall */
 //                     if (update) {
 //                             DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 //                     }
@@ -248,34 +247,27 @@ int EM_mask_init_backbuf_border(ViewContext *vc, short mcords[][2], short tot, s
        }
        else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
 
-       if(em_vertoffs==0) return 0;
-       
        buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
        if(buf==NULL) return 0;
+       if(em_vertoffs==0) return 0;
 
        dr = buf->rect;
 
        /* draw the mask */
-#ifdef __APPLE__
-       glDrawBuffer(GL_AUX0);
-#endif
        glDisable(GL_DEPTH_TEST);
        
-// XXX persp(PERSP_WIN);
        glColor3ub(0, 0, 0);
        
        /* yah, opengl doesn't do concave... tsk! */
+       ED_region_pixelspace(vc->ar);
        draw_triangulated(mcords, tot); 
        
        glBegin(GL_LINE_LOOP);  /* for zero sized masks, lines */
        for(a=0; a<tot; a++) glVertex2s(mcords[a][0], mcords[a][1]);
        glEnd();
        
-// XXX persp(PERSP_VIEW);
        glFinish();     /* to be sure readpixels sees mask */
        
-       glDrawBuffer(GL_BACK);
-       
        /* grab mask */
        bufmask= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
        drm = bufmask->rect;
@@ -309,11 +301,11 @@ int EM_init_backbuf_circle(ViewContext *vc, short xs, short ys, short rads)
                else return 0;
        }
        else if(vc->v3d->drawtype<OB_SOLID || (vc->v3d->flag & V3D_ZBUF_SELECT)==0) return 0;
-       if(em_vertoffs==0) return 0;
        
        xmin= xs-rads; xmax= xs+rads;
        ymin= ys-rads; ymax= ys+rads;
        buf= view3d_read_backbuf(vc, xmin, ymin, xmax, ymax);
+       if(em_vertoffs==0) return 0;
        if(buf==NULL) return 0;
 
        dr = buf->rect;
@@ -366,9 +358,9 @@ static void findnearestvert__doClosest(void *userData, EditVert *eve, int x, int
 
 
 
-static unsigned int findnearestvert__backbufIndextest(unsigned int index)
+static unsigned int findnearestvert__backbufIndextest(void *handle, unsigned int index)
 {
-       EditMesh *em= NULL; // XXX
+       EditMesh *em= (EditMesh *)handle;
        EditVert *eve = BLI_findlink(&em->verts, index-1);
 
        if(eve && (eve->f & SELECT)) return 0;
@@ -390,8 +382,8 @@ EditVert *findnearestvert(ViewContext *vc, int *dist, short sel, short strict)
                unsigned int index;
                EditVert *eve;
                
-               if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, strict, findnearestvert__backbufIndextest); 
-               else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, 0, NULL); 
+               if(strict) index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, strict, vc->em, findnearestvert__backbufIndextest); 
+               else index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_wireoffs, 0xFFFFFF, &distance, 0, NULL, NULL); 
                
                eve = BLI_findlink(&vc->em->verts, index-1);
                
@@ -468,7 +460,7 @@ static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, in
                
        if(eed->f & SELECT) distance+=5;
        if(distance < data->dist) {
-               if(data->vc.v3d->flag & V3D_CLIPPING) {
+               if(data->vc.rv3d->rflag & RV3D_CLIPPING) {
                        float labda= labda_PdistVL2Dfl(data->mval, v1, v2);
                        float vec[3];
 
@@ -477,7 +469,7 @@ static void findnearestedge__doClosest(void *userData, EditEdge *eed, int x0, in
                        vec[2]= eed->v1->co[2] + labda*(eed->v2->co[2] - eed->v1->co[2]);
                        Mat4MulVecfl(data->vc.obedit->obmat, vec);
 
-                       if(view3d_test_clipping(data->vc.v3d, vec)==0) {
+                       if(view3d_test_clipping(data->vc.rv3d, vec)==0) {
                                data->dist = distance;
                                data->closest = eed;
                        }
@@ -493,7 +485,7 @@ EditEdge *findnearestedge(ViewContext *vc, int *dist)
 
        if(vc->v3d->drawtype>OB_WIRE && (vc->v3d->flag & V3D_ZBUF_SELECT)) {
                int distance;
-               unsigned int index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_solidoffs, em_wireoffs, &distance,0, NULL);
+               unsigned int index = view3d_sample_backbuf_rect(vc, vc->mval, 50, em_solidoffs, em_wireoffs, &distance,0, NULL, NULL);
                EditEdge *eed = BLI_findlink(&vc->em->edges, index-1);
 
                if (eed && distance<*dist) {
@@ -624,6 +616,9 @@ static int unified_findnearest(ViewContext *vc, EditVert **eve, EditEdge **eed,
        *eed= NULL;
        *efa= NULL;
        
+       /* no afterqueue (yet), so we check it now, otherwise the em_xxxofs indices are bad */
+       view3d_validate_backbuf(vc);
+       
        if(em->selectmode & SCE_SELECT_VERTEX)
                *eve= findnearestvert(vc, &dist, SELECT, 0);
        if(em->selectmode & SCE_SELECT_FACE)
@@ -644,23 +639,36 @@ static int unified_findnearest(ViewContext *vc, EditVert **eve, EditEdge **eed,
        return (*eve || *eed || *efa);
 }
 
+
+/* ****************  SIMILAR "group" SELECTS. FACE, EDGE AND VERTEX ************** */
+
+/* selects new faces/edges/verts based on the existing selection */
+
+/* FACES GROUP */
+
+#define SIMFACE_MATERIAL       201
+#define SIMFACE_IMAGE          202
+#define SIMFACE_AREA           203
+#define SIMFACE_PERIMETER      204
+#define SIMFACE_NORMAL         205
+#define SIMFACE_COPLANAR       206
+
+static EnumPropertyItem prop_simface_types[] = {
+       {SIMFACE_MATERIAL, "MATERIAL", 0, "Material", ""},
+       {SIMFACE_IMAGE, "IMAGE", 0, "Image", ""},
+       {SIMFACE_AREA, "AREA", 0, "Area", ""},
+       {SIMFACE_PERIMETER, "PERIMETER", 0, "Perimeter", ""},
+       {SIMFACE_NORMAL, "NORMAL", 0, "Normal", ""},
+       {SIMFACE_COPLANAR, "COPLANAR", 0, "Co-planar", ""},
+       {0, NULL, 0, NULL, NULL}
+};
+
+
 /* this as a way to compare the ares, perim  of 2 faces thay will scale to different sizes
- *0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */
+*0.5 so smaller faces arnt ALWAYS selected with a thresh of 1.0 */
 #define SCALE_CMP(a,b) ((a+a*thresh >= b) && (a-(a*thresh*0.5) <= b))
 
-/* ****************  GROUP SELECTS ************** */
-/* selects new faces/edges/verts based on the
- existing selection
-
-FACES GROUP
- mode 1: same material
- mode 2: same image
- mode 3: same area
- mode 4: same perimeter
- mode 5: same normal
- mode 6: same co-planer
-*/
-int facegroup_select(EditMesh *em, short mode)
+static int similar_face_select__internal(Scene *scene, EditMesh *em, int mode)
 {
        EditFace *efa, *base_efa=NULL;
        unsigned int selcount=0; /*count how many new faces we select*/
@@ -668,9 +676,8 @@ int facegroup_select(EditMesh *em, short mode)
        /*deselcount, count how many deselected faces are left, so we can bail out early
        also means that if there are no deselected faces, we can avoid a lot of looping */
        unsigned int deselcount=0; 
-       
+       float thresh= scene->toolsettings->select_thresh;
        short ok=0;
-       float thresh=0; // XXX scene->toolsettings->select_thresh;
        
        for(efa= em->faces.first; efa; efa= efa->next) {
                if (!efa->h) {
@@ -687,12 +694,11 @@ int facegroup_select(EditMesh *em, short mode)
        if (!ok || !deselcount) /* no data selected OR no more data to select */
                return 0;
        
-       /*if mode is 3 then record face areas, 4 record perimeter */
-       if (mode==3) {
+       if (mode==SIMFACE_AREA) {
                for(efa= em->faces.first; efa; efa= efa->next) {
                        efa->tmp.fp= EM_face_area(efa);
                }
-       } else if (mode==4) {
+       } else if (mode==SIMFACE_PERIMETER) {
                for(efa= em->faces.first; efa; efa= efa->next) {
                        efa->tmp.fp= EM_face_perimeter(efa);
                }
@@ -700,7 +706,7 @@ int facegroup_select(EditMesh *em, short mode)
        
        for(base_efa= em->faces.first; base_efa; base_efa= base_efa->next) {
                if (base_efa->f1) { /* This was one of the faces originaly selected */
-                       if (mode==1) { /* same material */
+                       if (mode==SIMFACE_MATERIAL) { /* same material */
                                for(efa= em->faces.first; efa; efa= efa->next) {
                                        if (
                                                !(efa->f & SELECT) &&
@@ -714,7 +720,7 @@ int facegroup_select(EditMesh *em, short mode)
                                                        return selcount;
                                        }
                                }
-                       } else if (mode==2) { /* same image */
+                       } else if (mode==SIMFACE_IMAGE) { /* same image */
                                MTFace *tf, *base_tf;
 
                                base_tf = (MTFace*)CustomData_em_get(&em->fdata, base_efa->data,
@@ -737,7 +743,7 @@ int facegroup_select(EditMesh *em, short mode)
                                                }
                                        }
                                }
-                       } else if (mode==3 || mode==4) { /* same area OR same perimeter, both use the same temp var */
+                       } else if (mode==SIMFACE_AREA || mode==SIMFACE_PERIMETER) { /* same area OR same perimeter, both use the same temp var */
                                for(efa= em->faces.first; efa; efa= efa->next) {
                                        if (
                                                (!(efa->f & SELECT) && !efa->h) &&
@@ -750,7 +756,7 @@ int facegroup_select(EditMesh *em, short mode)
                                                        return selcount;
                                        }
                                }
-                       } else if (mode==5) { /* same normal */
+                       } else if (mode==SIMFACE_NORMAL) {
                                float angle;
                                for(efa= em->faces.first; efa; efa= efa->next) {
                                        if (!(efa->f & SELECT) && !efa->h) {
@@ -764,7 +770,7 @@ int facegroup_select(EditMesh *em, short mode)
                                                }
                                        }
                                }
-                       } else if (mode==6) { /* same planer */
+                       } else if (mode==SIMFACE_COPLANAR) { /* same planer */
                                float angle, base_dot, dot;
                                base_dot= Inpf(base_efa->cent, base_efa->n);
                                for(efa= em->faces.first; efa; efa= efa->next) {
@@ -788,23 +794,51 @@ int facegroup_select(EditMesh *em, short mode)
        return selcount;
 }
 
+static int similar_face_select_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       Mesh *me= obedit->data;
+       EditMesh *em= BKE_mesh_get_editmesh(me); 
 
-/*
-EDGE GROUP
- mode 1: same length
- mode 2: same direction
- mode 3: same number of face users
- mode 4: similar face angles.
- mode 5: similar crease
- mode 6: similar seam
- mode 7: similar sharp
-*/
-
-/* this function is only used by edgegroup_select's edge angle */
-
-
+       int selcount = similar_face_select__internal(scene, em, RNA_int_get(op->ptr, "type"));
+       
+       if (selcount) {
+               /* here was an edge-mode only select flush case, has to be generalized */
+               EM_selectmode_flush(em);
+               WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+               BKE_mesh_end_editmesh(me, em);
+               return OPERATOR_FINISHED;
+       }
+       
+       BKE_mesh_end_editmesh(me, em);
+       return OPERATOR_CANCELLED;
+}      
 
-static int edgegroup_select__internal(EditMesh *em, short mode)
+/* ***************************************************** */
+
+/* EDGE GROUP */
+
+#define SIMEDGE_LENGTH         101
+#define SIMEDGE_DIR                    102
+#define SIMEDGE_FACE           103
+#define SIMEDGE_FACE_ANGLE     104
+#define SIMEDGE_CREASE         105
+#define SIMEDGE_SEAM           106
+#define SIMEDGE_SHARP          107
+
+static EnumPropertyItem prop_simedge_types[] = {
+       {SIMEDGE_LENGTH, "LENGTH", 0, "Length", ""},
+       {SIMEDGE_DIR, "DIR", 0, "Direction", ""},
+       {SIMEDGE_FACE, "FACE", 0, "Amount of Vertices in Face", ""},
+       {SIMEDGE_FACE_ANGLE, "FACE_ANGLE", 0, "Face Angles", ""},
+       {SIMEDGE_CREASE, "CREASE", 0, "Crease", ""},
+       {SIMEDGE_SEAM, "SEAM", 0, "Seam", ""},
+       {SIMEDGE_SHARP, "SHARP", 0, "Sharpness", ""},
+       {0, NULL, 0, NULL, NULL}
+};
+
+static int similar_edge_select__internal(Scene *scene, EditMesh *em, int mode)
 {
        EditEdge *eed, *base_eed=NULL;
        unsigned int selcount=0; /* count how many new edges we select*/
@@ -814,7 +848,7 @@ static int edgegroup_select__internal(EditMesh *em, short mode)
        unsigned int deselcount=0;
        
        short ok=0;
-       float thresh=0; // XXX scene->toolsettings->select_thresh;
+       float thresh= scene->toolsettings->select_thresh;
        
        for(eed= em->edges.first; eed; eed= eed->next) {
                if (!eed->h) {
@@ -828,19 +862,19 @@ static int edgegroup_select__internal(EditMesh *em, short mode)
                        /* set all eed->tmp.l to 0 we use it later.
                        for counting face users*/
                        eed->tmp.l=0;
-                       eed->f2=0; /* only for mode 4, edge animations */
+                       eed->f2=0; /* only for mode SIMEDGE_FACE_ANGLE, edge animations */
                }
        }
        
        if (!ok || !deselcount) /* no data selected OR no more data to select*/
                return 0;
        
-       if (mode==1) { /*store length*/
+       if (mode==SIMEDGE_LENGTH) { /*store length*/
                for(eed= em->edges.first; eed; eed= eed->next) {
                        if (!eed->h) /* dont calc data for hidden edges*/
                                eed->tmp.fp= VecLenf(eed->v1->co, eed->v2->co);
                }
-       } else if (mode==3) { /*store face users*/
+       } else if (mode==SIMEDGE_FACE) { /*store face users*/
                EditFace *efa;
                /* cound how many faces each edge uses use tmp->l */
                for(efa= em->faces.first; efa; efa= efa->next) {
@@ -849,7 +883,7 @@ static int edgegroup_select__internal(EditMesh *em, short mode)
                        efa->e3->tmp.l++;
                        if (efa->e4) efa->e4->tmp.l++;
                }
-       } else if (mode==4) { /*store edge angles */
+       } else if (mode==SIMEDGE_FACE_ANGLE) { /*store edge angles */
                EditFace *efa;
                int j;
                /* cound how many faces each edge uses use tmp.l */
@@ -891,7 +925,7 @@ static int edgegroup_select__internal(EditMesh *em, short mode)
        
        for(base_eed= em->edges.first; base_eed; base_eed= base_eed->next) {
                if (base_eed->f1) {
-                       if (mode==1) { /* same length */
+                       if (mode==SIMEDGE_LENGTH) { /* same length */
                                for(eed= em->edges.first; eed; eed= eed->next) {
                                        if (
                                                !(eed->f & SELECT) &&
@@ -905,7 +939,7 @@ static int edgegroup_select__internal(EditMesh *em, short mode)
                                                        return selcount;
                                        }
                                }
-                       } else if (mode==2) { /* same direction */
+                       } else if (mode==SIMEDGE_DIR) { /* same direction */
                                float base_dir[3], dir[3], angle;
                                VecSubf(base_dir, base_eed->v1->co, base_eed->v2->co);
                                for(eed= em->edges.first; eed; eed= eed->next) {
@@ -925,7 +959,7 @@ static int edgegroup_select__internal(EditMesh *em, short mode)
                                                }
                                        }
                                }
-                       } else if (mode==3) { /* face users */                          
+                       } else if (mode==SIMEDGE_FACE) { /* face users */                               
                                for(eed= em->edges.first; eed; eed= eed->next) {
                                        if (
                                                !(eed->f & SELECT) &&
@@ -939,7 +973,7 @@ static int edgegroup_select__internal(EditMesh *em, short mode)
                                                        return selcount;
                                        }
                                }
-                       } else if (mode==4 && base_eed->f2==2) { /* edge angles, f2==2 means the edge has an angle. */                          
+                       } else if (mode==SIMEDGE_FACE_ANGLE && base_eed->f2==2) { /* edge angles, f2==2 means the edge has an angle. */                         
                                for(eed= em->edges.first; eed; eed= eed->next) {
                                        if (
                                                !(eed->f & SELECT) &&
@@ -954,7 +988,7 @@ static int edgegroup_select__internal(EditMesh *em, short mode)
                                                        return selcount;
                                        }
                                }
-                       } else if (mode==5) { /* edge crease */
+                       } else if (mode==SIMEDGE_CREASE) { /* edge crease */
                                for(eed= em->edges.first; eed; eed= eed->next) {
                                        if (
                                                !(eed->f & SELECT) &&
@@ -968,7 +1002,7 @@ static int edgegroup_select__internal(EditMesh *em, short mode)
                                                        return selcount;
                                        }
                                }
-                       } else if (mode==6) { /* edge seam */
+                       } else if (mode==SIMEDGE_SEAM) { /* edge seam */
                                for(eed= em->edges.first; eed; eed= eed->next) {
                                        if (
                                                !(eed->f & SELECT) &&
@@ -982,7 +1016,7 @@ static int edgegroup_select__internal(EditMesh *em, short mode)
                                                        return selcount;
                                        }
                                }
-                       } else if (mode==7) { /* edge sharp */
+                       } else if (mode==SIMEDGE_SHARP) { /* edge sharp */
                                for(eed= em->edges.first; eed; eed= eed->next) {
                                        if (
                                                !(eed->f & SELECT) &&
@@ -1002,29 +1036,28 @@ static int edgegroup_select__internal(EditMesh *em, short mode)
        return selcount;
 }
 /* wrap the above function but do selection flushing edge to face */
-int edgegroup_select(EditMesh *em, short mode)
+static int similar_edge_select_exec(bContext *C, wmOperator *op)
 {
-       int selcount = edgegroup_select__internal(em, mode);
+       Scene *scene= CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       Mesh *me= obedit->data;
+       EditMesh *em= BKE_mesh_get_editmesh(me); 
+
+       int selcount = similar_edge_select__internal(scene, em, RNA_int_get(op->ptr, "type"));
        
        if (selcount) {
-               /* Could run a generic flush function,
-                * but the problem is only that all edges of a face
-                * can be selected without the face becoming selected */
-               EditFace *efa;
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       if (efa->v4) {
-                               if (efa->e1->f&SELECT && efa->e2->f&SELECT && efa->e3->f&SELECT && efa->e4->f&SELECT)
-                                       efa->f |= SELECT;
-                       }  else {
-                               if (efa->e1->f&SELECT && efa->e2->f&SELECT && efa->e3->f&SELECT)
-                                       efa->f |= SELECT;
-                       }
-               }
+               /* here was an edge-mode only select flush case, has to be generalized */
+               EM_selectmode_flush(em);
+               WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+               BKE_mesh_end_editmesh(me, em);
+               return OPERATOR_FINISHED;
        }
-       return selcount;
+       
+       BKE_mesh_end_editmesh(me, em);
+       return OPERATOR_CANCELLED;
 }
 
-
+/* ********************************* */
 
 /*
 VERT GROUP
@@ -1032,18 +1065,35 @@ VERT GROUP
  mode 2: same number of face users
  mode 3: same vertex groups
 */
-int vertgroup_select(EditMesh *em, short mode)
+
+#define SIMVERT_NORMAL 0
+#define SIMVERT_FACE   1
+#define SIMVERT_VGROUP 2
+
+static EnumPropertyItem prop_simvertex_types[] = {
+       {SIMVERT_NORMAL, "NORMAL", 0, "Normal", ""},
+       {SIMVERT_FACE, "FACE", 0, "Amount of Vertices in Face", ""},
+       {SIMVERT_VGROUP, "VGROUP", 0, "Vertex Groups", ""},
+       {0, NULL, 0, NULL, NULL}
+};
+
+
+static int similar_vert_select_exec(bContext *C, wmOperator *op)
 {
+       Scene *scene= CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       Mesh *me= obedit->data;
+       EditMesh *em= BKE_mesh_get_editmesh(me); 
        EditVert *eve, *base_eve=NULL;
-       
        unsigned int selcount=0; /* count how many new edges we select*/
        
        /*count how many visible selected edges there are,
        so we can return when there are none left */
        unsigned int deselcount=0;
+       int mode= RNA_enum_get(op->ptr, "type");
        
        short ok=0;
-       float thresh=0; // XXX scene->toolsettings->select_thresh;
+       float thresh= scene->toolsettings->select_thresh;
        
        for(eve= em->verts.first; eve; eve= eve->next) {
                if (!eve->h) {
@@ -1060,11 +1110,13 @@ int vertgroup_select(EditMesh *em, short mode)
                
        }
        
-       if (!ok || !deselcount) /* no data selected OR no more data to select*/
+       if (!ok || !deselcount) { /* no data selected OR no more data to select*/
+               BKE_mesh_end_editmesh(me, em);
                return 0;
+       }
        
-       
-       if (mode==2) { /* store face users */
+       if(mode == SIMVERT_FACE) {
+               /* store face users */
                EditFace *efa;
                
                /* count how many faces each edge uses use tmp->l */
@@ -1080,7 +1132,7 @@ int vertgroup_select(EditMesh *em, short mode)
        for(base_eve= em->verts.first; base_eve; base_eve= base_eve->next) {
                if (base_eve->f1) {
                                
-                       if (mode==1) { /* same normal */
+                       if(mode == SIMVERT_NORMAL) {
                                float angle;
                                for(eve= em->verts.first; eve; eve= eve->next) {
                                        if (!(eve->f & SELECT) && !eve->h) {
@@ -1089,12 +1141,15 @@ int vertgroup_select(EditMesh *em, short mode)
                                                        eve->f |= SELECT;
                                                        selcount++;
                                                        deselcount--;
-                                                       if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                                       if (!deselcount) {/*have we selected all posible faces?, if so return*/
+                                                               BKE_mesh_end_editmesh(me, em);
                                                                return selcount;
+                                                       }
                                                }
                                        }
                                }
-                       } else if (mode==2) { /* face users */
+                       }
+                       else if(mode == SIMVERT_FACE) {
                                for(eve= em->verts.first; eve; eve= eve->next) {
                                        if (
                                                !(eve->f & SELECT) &&
@@ -1104,19 +1159,24 @@ int vertgroup_select(EditMesh *em, short mode)
                                                eve->f |= SELECT;
                                                selcount++;
                                                deselcount--;
-                                               if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                               if (!deselcount) {/*have we selected all posible faces?, if so return*/
+                                                       BKE_mesh_end_editmesh(me, em);
                                                        return selcount;
+                                               }
                                        }
                                }
-                       } else if (mode==3) { /* vertex groups */
+                       } 
+                       else if(mode == SIMVERT_VGROUP) {
                                MDeformVert *dvert, *base_dvert;
                                short i, j; /* weight index */
 
                                base_dvert= CustomData_em_get(&em->vdata, base_eve->data,
                                        CD_MDEFORMVERT);
 
-                               if (!base_dvert || base_dvert->totweight == 0)
+                               if (!base_dvert || base_dvert->totweight == 0) {
+                                       BKE_mesh_end_editmesh(me, em);
                                        return selcount;
+                               }
                                
                                for(eve= em->verts.first; eve; eve= eve->next) {
                                        dvert= CustomData_em_get(&em->vdata, eve->data,
@@ -1131,8 +1191,10 @@ int vertgroup_select(EditMesh *em, short mode)
                                                                        eve->f |= SELECT;
                                                                        selcount++;
                                                                        deselcount--;
-                                                                       if (!deselcount) /*have we selected all posible faces?, if so return*/
+                                                                       if (!deselcount) { /*have we selected all posible faces?, if so return*/
+                                                                               BKE_mesh_end_editmesh(me, em);
                                                                                return selcount;
+                                                                       }
                                                                        break;
                                                                }
                                                        }
@@ -1142,86 +1204,91 @@ int vertgroup_select(EditMesh *em, short mode)
                        }
                }
        } /* end basevert loop */
-       return selcount;
-}
 
-/* EditMode menu triggered from space.c by pressing Shift+G
-handles face/edge vert context and
-facegroup_select/edgegroup_select/vertgroup_select do all the work
-*/
+       if(selcount) {
+               WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+               BKE_mesh_end_editmesh(me, em);
+               return OPERATOR_FINISHED;
+       }
+
+       BKE_mesh_end_editmesh(me, em);
+       return OPERATOR_CANCELLED;
+}
 
-void select_mesh_group_menu(EditMesh *em)
+static int select_similar_exec(bContext *C, wmOperator *op)
 {
-       short ret;
-       int selcount, first_item=1, multi=0;
-       char str[512] = "Select Similar "; /* total max length is 404 at the moment */
-       
-       if (!ELEM3(em->selectmode, SCE_SELECT_VERTEX, SCE_SELECT_EDGE, SCE_SELECT_FACE)) {
-               multi=1;
-       }
-       
-       if(em->selectmode & SCE_SELECT_VERTEX) {
-               if (multi) strcat(str, "%t|Vertices%x-1|");
-               else strcat(str, "Vertices %t|");
-               strcat(str, "    Normal %x1|    Face Users %x2|    Shared Vertex Groups%x3");
-               first_item=0;
-       }
+       int type= RNA_enum_get(op->ptr, "type");
+
+       if(type < 100)
+               return similar_vert_select_exec(C, op);
+       else if(type < 200)
+               return similar_edge_select_exec(C, op);
+       else
+               return similar_face_select_exec(C, op);
+}
 
-       if(em->selectmode & SCE_SELECT_EDGE) {
-               if (multi) {
-                       if (first_item) strcat(str, "%t|Edges%x-1|");
-                       else strcat(str, "|%l|Edges%x-1|");
-               } else strcat(str, "Edges %t|");
+static EnumPropertyItem *select_similar_type_itemf(bContext *C, PointerRNA *ptr, int *free)
+{
+       Object *obedit;
+       EnumPropertyItem *item= NULL;
+       int totitem= 0;
+       
+       if(C==NULL) {
+               /* needed for doc generation */
+               RNA_enum_items_add(&item, &totitem, prop_simvertex_types);
+               RNA_enum_items_add(&item, &totitem, prop_simedge_types);
+               RNA_enum_items_add(&item, &totitem, prop_simface_types);
+               RNA_enum_item_end(&item, &totitem);
+               *free= 1;
                
-               strcat(str, "    Length %x10|    Direction %x20|    Face Users%x30|    Face Angle%x40|    Crease%x50|    Seam%x60|    Sharp%x70");
-               first_item=0;
+               return item;
        }
        
-       if(em->selectmode & SCE_SELECT_FACE) {
-               if (multi) {
-                       strcat(str, "|%l|Faces%x-1|");
-               } else strcat(str, "Faces %t|");
-               strcat(str, "    Material %x100|    Image %x200|    Area %x300|    Perimeter %x400|    Normal %x500|    Co-Planar %x600");
+       obedit= CTX_data_edit_object(C);
        
+       if(obedit && obedit->type == OB_MESH) {
+               EditMesh *em= BKE_mesh_get_editmesh(obedit->data); 
+
+               if(em->selectmode & SCE_SELECT_VERTEX)
+                       RNA_enum_items_add(&item, &totitem, prop_simvertex_types);
+               else if(em->selectmode & SCE_SELECT_EDGE)
+                       RNA_enum_items_add(&item, &totitem, prop_simedge_types);
+               else if(em->selectmode & SCE_SELECT_FACE)
+                       RNA_enum_items_add(&item, &totitem, prop_simface_types);
+               RNA_enum_item_end(&item, &totitem);
+
+               *free= 1;
+
+               return item;
        }
        
-       ret= pupmenu(str);
-       if (ret<1) return;
+       return NULL;
+}
+
+void MESH_OT_select_similar(wmOperatorType *ot)
+{
+       PropertyRNA *prop;
+
+       /* identifiers */
+       ot->name= "Select Similar";
+       ot->idname= "MESH_OT_select_similar";
        
-       if (ret<10) {
-               selcount= vertgroup_select(em, ret);
-               if (selcount) { /* update if data was selected */
-                       EM_select_flush(em); /* so that selected verts, go onto select faces */
-                       G.totvertsel += selcount;
-//                     if (EM_texFaceCheck())
-                       BIF_undo_push("Select Similar Vertices");
-               }
-               return;
-       }
+       /* api callbacks */
+       ot->invoke= WM_menu_invoke;
+       ot->exec= select_similar_exec;
+       ot->poll= ED_operator_editmesh;
        
-       if (ret<100) {
-               selcount= edgegroup_select(em, ret/10);
-               
-               if (selcount) { /* update if data was selected */
-                       /*EM_select_flush(em);*/ /* dont use because it can end up selecting more edges and is not usefull*/
-                       G.totedgesel+=selcount;
-//                     if (EM_texFaceCheck())
-                       BIF_undo_push("Select Similar Edges");
-               }
-               return;
-       }
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
-       if (ret<1000) {
-               selcount= facegroup_select(em, ret/100);
-               if (selcount) { /* update if data was selected */
-                       G.totfacesel+=selcount;
-//                     if (EM_texFaceCheck())
-                       BIF_undo_push("Select Similar Faces");
-               }
-               return;
-       }
+       /* properties */
+       prop= RNA_def_enum(ot->srna, "type", prop_simvertex_types, 0, "Type", "");
+       RNA_def_enum_funcs(prop, select_similar_type_itemf);
 }
 
+/* ******************************************* */
+
+
 int mesh_layers_menu_charlen(CustomData *data, int type)
 {
        int i, len = 0;
@@ -1238,7 +1305,8 @@ int mesh_layers_menu_charlen(CustomData *data, int type)
 
 /* this function adds menu text into an existing string.
  * this string's size should be allocated with mesh_layers_menu_charlen */
-void mesh_layers_menu_concat(CustomData *data, int type, char *str) {
+void mesh_layers_menu_concat(CustomData *data, int type, char *str) 
+{
        int i, count = 0;
        char *str_pt = str;
        CustomDataLayer *layer;
@@ -1345,11 +1413,10 @@ void EM_mesh_copy_edge(EditMesh *em, short type)
        if (change) {
 //             DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
                
-               BIF_undo_push("Copy Edge Attribute");
        }
 }
 
-void EM_mesh_copy_face(EditMesh *em, short type)
+void EM_mesh_copy_face(EditMesh *em, wmOperator *op, short type)
 {
        short change=0;
        
@@ -1375,7 +1442,7 @@ void EM_mesh_copy_face(EditMesh *em, short type)
                break;
        case 2: /* copy image */
                if (!tf_act) {
-                       error("mesh has no uv/image layers");
+                       BKE_report(op->reports, RPT_ERROR, "Mesh has no uv/image layers.");
                        return;
                }
                for(efa=em->faces.first; efa; efa=efa->next) {
@@ -1396,7 +1463,7 @@ void EM_mesh_copy_face(EditMesh *em, short type)
 
        case 3: /* copy UV's */
                if (!tf_act) {
-                       error("mesh has no uv/image layers");
+                       BKE_report(op->reports, RPT_ERROR, "Mesh has no uv/image layers.");
                        return;
                }
                for(efa=em->faces.first; efa; efa=efa->next) {
@@ -1409,7 +1476,7 @@ void EM_mesh_copy_face(EditMesh *em, short type)
                break;
        case 4: /* mode's */
                if (!tf_act) {
-                       error("mesh has no uv/image layers");
+                       BKE_report(op->reports, RPT_ERROR, "Mesh has no uv/image layers.");
                        return;
                }
                for(efa=em->faces.first; efa; efa=efa->next) {
@@ -1422,7 +1489,7 @@ void EM_mesh_copy_face(EditMesh *em, short type)
                break;
        case 5: /* copy transp's */
                if (!tf_act) {
-                       error("mesh has no uv/image layers");
+                       BKE_report(op->reports, RPT_ERROR, "Mesh has no uv/image layers.");
                        return;
                }
                for(efa=em->faces.first; efa; efa=efa->next) {
@@ -1436,7 +1503,7 @@ void EM_mesh_copy_face(EditMesh *em, short type)
 
        case 6: /* copy vcols's */
                if (!mcol_act) {
-                       error("mesh has no color layers");
+                       BKE_report(op->reports, RPT_ERROR, "Mesh has no color layers.");
                        return;
                } else {
                        /* guess the 4th color if needs be */
@@ -1473,16 +1540,12 @@ void EM_mesh_copy_face(EditMesh *em, short type)
        
        if (change) {
 //             DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-               if (type==3) {
-// XXX                 allqueue(REDRAWIMAGE, 0);                       
-               }
                
-               BIF_undo_push("Copy Face Attribute");
        }
 }
 
 
-void EM_mesh_copy_face_layer(EditMesh *em, short type) 
+void EM_mesh_copy_face_layer(EditMesh *em, wmOperator *op, short type) 
 {
        short change=0;
        
@@ -1497,7 +1560,7 @@ void EM_mesh_copy_face_layer(EditMesh *em, short type)
        case 8:
        case 9:
                if (CustomData_number_of_layers(&em->fdata, CD_MTFACE)<2) {
-                       error("mesh does not have multiple uv/image layers");
+                       BKE_report(op->reports, RPT_ERROR, "mesh does not have multiple uv/image layers");
                        return;
                } else {
                        int layer_orig_idx, layer_idx;
@@ -1524,7 +1587,7 @@ void EM_mesh_copy_face_layer(EditMesh *em, short type)
 
        case 10: /* select vcol layers - make sure this stays in sync with above code */
                if (CustomData_number_of_layers(&em->fdata, CD_MCOL)<2) {
-                       error("mesh does not have multiple color layers");
+                       BKE_report(op->reports, RPT_ERROR, "mesh does not have multiple color layers");
                        return;
                } else {
                        int layer_orig_idx, layer_idx;
@@ -1608,13 +1671,12 @@ void EM_mesh_copy_face_layer(EditMesh *em, short type)
        if (change) {
 //             DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
                
-               BIF_undo_push("Copy Face Layer");
        }
 }
 
 
 /* ctrl+c in mesh editmode */
-void mesh_copy_menu(EditMesh *em)
+void mesh_copy_menu(EditMesh *em, wmOperator *op)
 {
        EditSelection *ese;
        int ret;
@@ -1646,9 +1708,9 @@ void mesh_copy_menu(EditMesh *em)
                if (ret<1) return;
                
                if (ret<=6) {
-                       EM_mesh_copy_face(em, ret);
+                       EM_mesh_copy_face(em, op, ret);
                } else {
-                       EM_mesh_copy_face_layer(em, ret);
+                       EM_mesh_copy_face_layer(em, op, ret);
                }
        }
 }
@@ -1887,16 +1949,21 @@ static void edgering_select(EditMesh *em, EditEdge *startedge, int select)
        }
 }
 
-void loop_multiselect(EditMesh *em, int looptype)
+static int loop_multiselect(bContext *C, wmOperator *op)
 {
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
        EditEdge *eed;
        EditEdge **edarray;
        int edindex, edfirstcount;
+       int looptype= RNA_boolean_get(op->ptr, "ring");
+       
+       /* sets em->totedgesel */
+       EM_nedges_selected(em);
        
-       /*edarray = MEM_mallocN(sizeof(*edarray)*G.totedgesel,"edge array");*/
-       edarray = MEM_mallocN(sizeof(EditEdge*)*G.totedgesel,"edge array");
+       edarray = MEM_mallocN(sizeof(EditEdge*)*em->totedgesel,"edge array");
        edindex = 0;
-       edfirstcount = G.totedgesel;
+       edfirstcount = em->totedgesel;
        
        for(eed=em->edges.first; eed; eed=eed->next){
                if(eed->f&SELECT){
@@ -1911,7 +1978,6 @@ void loop_multiselect(EditMesh *em, int looptype)
                        edgering_select(em, eed,SELECT);
                }
                EM_selectmode_flush(em);
-               BIF_undo_push("Edge Ring Multi-Select");
        }
        else{
                for(edindex = 0; edindex < edfirstcount; edindex +=1){
@@ -1919,115 +1985,214 @@ void loop_multiselect(EditMesh *em, int looptype)
                        edgeloop_select(em, eed,SELECT);
                }
                EM_selectmode_flush(em);
-               BIF_undo_push("Edge Loop Multi-Select");
        }
        MEM_freeN(edarray);
 //     if (EM_texFaceCheck())
+       
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;       
+}
+
+void MESH_OT_loop_multi_select(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Multi Select Loops";
+       ot->idname= "MESH_OT_loop_multi_select";
+       
+       /* api callbacks */
+       ot->exec= loop_multiselect;
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* properties */
+       RNA_def_boolean(ot->srna, "ring", 0, "Ring", "");
 }
+
                
 /* ***************** MAIN MOUSE SELECTION ************** */
 
-/* just to have the functions nice together */
 
-static void mouse_mesh_loop(ViewContext *vc)
+/* ***************** loop select (non modal) ************** */
+
+static void mouse_mesh_loop(bContext *C, short mval[2], short extend, short ring)
 {
-       EditMesh *em= vc->em;
+       ViewContext vc;
+       EditMesh *em;
        EditEdge *eed;
        int select= 1;
        int dist= 50;
-       int shift= 0, alt= 0, ctrl= 0; // XXX
        
-       eed= findnearestedge(vc, &dist);
+       em_setup_viewcontext(C, &vc);
+       vc.mval[0]= mval[0];
+       vc.mval[1]= mval[1];
+       em= vc.em;
+       
+       eed= findnearestedge(&vc, &dist);
        if(eed) {
-               if (vc->scene->toolsettings->edge_mode == EDGE_MODE_SELECT) {
-                       if(shift==0) EM_clear_flag_all(em, SELECT);
-               
-                       if((eed->f & SELECT)==0) select=1;
-                       else if(shift) select=0;
+               if(extend==0) EM_clear_flag_all(em, SELECT);
+       
+               if((eed->f & SELECT)==0) select=1;
+               else if(extend) select=0;
 
-                       if(em->selectmode & SCE_SELECT_FACE) {
-                               faceloop_select(em, eed, select);
-                       }
-                       else if(em->selectmode & SCE_SELECT_EDGE) {
-                       if((alt && ctrl))
-                                       edgering_select(em, eed, select);
-                       else if(alt)
-                                       edgeloop_select(em, eed, select);
-                       }
-                   else if(em->selectmode & SCE_SELECT_VERTEX) {
-                       if((alt && ctrl))
-                                       edgering_select(em, eed, select);
-                       else if(alt)
-                                       edgeloop_select(em, eed, select);
-                       }
+               if(em->selectmode & SCE_SELECT_FACE) {
+                       faceloop_select(em, eed, select);
+               }
+               else if(em->selectmode & SCE_SELECT_EDGE) {
+                       if(ring)
+                               edgering_select(em, eed, select);
+                       else
+                               edgeloop_select(em, eed, select);
+               }
+               else if(em->selectmode & SCE_SELECT_VERTEX) {
+                       if(ring)
+                               edgering_select(em, eed, select);
+                       else 
+                               edgeloop_select(em, eed, select);
+               }
 
-                       EM_selectmode_flush(em);
+               EM_selectmode_flush(em);
 //                     if (EM_texFaceCheck())
+               
+               WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
+       }
+}
+
+static int mesh_select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       
+       view3d_operator_needs_opengl(C);
+       
+       mouse_mesh_loop(C, event->mval, RNA_boolean_get(op->ptr, "extend"),
+                                       RNA_boolean_get(op->ptr, "ring"));
+       
+       /* cannot do tweaks for as long this keymap is after transform map */
+       return OPERATOR_FINISHED;
+}
+
+void MESH_OT_loop_select(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Loop Select";
+       ot->idname= "MESH_OT_loop_select";
+       
+       /* api callbacks */
+       ot->invoke= mesh_select_loop_invoke;
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* properties */
+       RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
+       RNA_def_boolean(ot->srna, "ring", 0, "Select Ring", "");
+}
+
+/* ******************* mesh shortest path select, uses prev-selected edge ****************** */
+
+/* since you want to create paths with multiple selects, it doesn't have extend option */
+static void mouse_mesh_shortest_path(bContext *C, short mval[2])
+{
+       ViewContext vc;
+       EditMesh *em;
+       EditEdge *eed;
+       int dist= 50;
+       
+       em_setup_viewcontext(C, &vc);
+       vc.mval[0]= mval[0];
+       vc.mval[1]= mval[1];
+       em= vc.em;
+       
+       eed= findnearestedge(&vc, &dist);
+       if(eed) {
+               Mesh *me= vc.obedit->data;
+               int path = 0;
+               
+               if (em->selected.last) {
+                       EditSelection *ese = em->selected.last;
                        
-               } 
-               else {
-                       int act = (edgetag_context_check(vc->scene, eed)==0);
-                       int path = 0;
-                       
-                       if (alt && ctrl && em->selected.last) {
-                               EditSelection *ese = em->selected.last;
-       
-                               if(ese && ese->type == EDITEDGE) {
-                                       EditEdge *eed_act;
-                                       eed_act = (EditEdge*)ese->data;
-                                       if (eed_act != eed) {
-                                               /* If shift is pressed we need to use the last active edge, (if it exists) */
-                                               if (edgetag_shortest_path(vc->scene, em, eed_act, eed)) {
-                                                       EM_remove_selection(em, eed_act, EDITEDGE);
-                                                       EM_select_edge(eed_act, 0);
-                                                       path = 1;
-                                               }
+                       if(ese && ese->type == EDITEDGE) {
+                               EditEdge *eed_act;
+                               eed_act = (EditEdge*)ese->data;
+                               if (eed_act != eed) {
+                                       if (edgetag_shortest_path(vc.scene, em, eed_act, eed)) {
+                                               EM_remove_selection(em, eed_act, EDITEDGE);
+                                               path = 1;
                                        }
                                }
                        }
-                       if (path==0) {
-                               edgetag_context_set(vc->scene, eed, act); /* switch the edge option */
-                       }
-                       
-                       if (act) {
-                               if ((eed->f & SELECT)==0) {
-                                       EM_select_edge(eed, 1);
-                                       EM_selectmode_flush(em);
-                               }
-                               /* even if this is selected it may not be in the selection list */
-                               EM_store_selection(em, eed, EDITEDGE);
-                       } else {
-                               if (eed->f & SELECT) {
-                                       EM_select_edge(eed, 0);
-                                       /* logic is differnt from above here since if this was selected we dont know if its in the selection list or not */
-                                       EM_remove_selection(em, eed, EDITEDGE);
-                                       
-                                       EM_selectmode_flush(em);
-                               }
-                       }
+               }
+               if (path==0) {
+                       int act = (edgetag_context_check(vc.scene, eed)==0);
+                       edgetag_context_set(vc.scene, eed, act); /* switch the edge option */
+               }
+               
+               EM_selectmode_flush(em);
+
+               /* even if this is selected it may not be in the selection list */
+               if(edgetag_context_check(vc.scene, eed)==0)
+                       EM_remove_selection(em, eed, EDITEDGE);
+               else
+                       EM_store_selection(em, eed, EDITEDGE);
+       
+               /* force drawmode for mesh */
+               switch (vc.scene->toolsettings->edge_mode) {
                        
-                       switch (0) { // XXX scene->toolsettings->edge_mode) {
                        case EDGE_MODE_TAG_SEAM:
-                               G.f |= G_DRAWSEAMS;
+                               me->drawflag |= ME_DRAWSEAMS;
                                break;
                        case EDGE_MODE_TAG_SHARP:
-                               G.f |= G_DRAWSHARP;
+                               me->drawflag |= ME_DRAWSHARP;
                                break;
                        case EDGE_MODE_TAG_CREASE:      
-                               G.f |= G_DRAWCREASES;
+                               me->drawflag |= ME_DRAWCREASES;
                                break;
                        case EDGE_MODE_TAG_BEVEL:
-                               G.f |= G_DRAWBWEIGHTS;
+                               me->drawflag |= ME_DRAWBWEIGHTS;
                                break;
-                       }
-                       
-//                     DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
                }
-                               
+               
+               DAG_object_flush_update(vc.scene, vc.obedit, OB_RECALC_DATA);
+       
+               WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
        }
 }
 
 
+static int mesh_shortest_path_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       
+       view3d_operator_needs_opengl(C);
+
+       mouse_mesh_shortest_path(C, event->mval);
+       
+       return OPERATOR_FINISHED;
+}
+       
+void MESH_OT_select_shortest_path(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Shortest Path Select";
+       ot->idname= "MESH_OT_select_shortest_path";
+       
+       /* api callbacks */
+       ot->invoke= mesh_shortest_path_select_invoke;
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* properties */
+       RNA_def_boolean(ot->srna, "extend", 0, "Extend Select", "");
+}
+
+
+/* ************************************************** */
+
+
 /* here actual select happens */
 /* gets called via generic mouse select operator */
 void mouse_mesh(bContext *C, short mval[2], short extend)
@@ -2036,15 +2201,13 @@ void mouse_mesh(bContext *C, short mval[2], short extend)
        EditVert *eve;
        EditEdge *eed;
        EditFace *efa;
-       int  alt= 0; // XXX
        
        /* setup view context for argument to callbacks */
        em_setup_viewcontext(C, &vc);
        vc.mval[0]= mval[0];
        vc.mval[1]= mval[1];
        
-       if(alt) mouse_mesh_loop(&vc);
-       else if(unified_findnearest(&vc, &eve, &eed, &efa)) {
+       if(unified_findnearest(&vc, &eve, &eed, &efa)) {
                
                if(extend==0) EM_clear_flag_all(vc.em, SELECT);
                
@@ -2095,75 +2258,157 @@ void mouse_mesh(bContext *C, short mval[2], short extend)
 
        WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, vc.obedit);
        
-//     rightmouse_transform();
 }
 
+/* *********** select linked ************* */
 
-void selectconnected_mesh_all(EditMesh *em)
-{
-       EditVert *v1,*v2;
-       EditEdge *eed;
-       short done=1, toggle=0;
+/* for use with selectconnected_delimit_mesh only! */
+#define is_edge_delimit_ok(eed) ((eed->tmp.l == 1) && (eed->seam==0))
+#define is_face_tag(efa) is_edge_delimit_ok(efa->e1) || is_edge_delimit_ok(efa->e2) || is_edge_delimit_ok(efa->e3) || (efa->v4 && is_edge_delimit_ok(efa->e4))
 
-       if(em->edges.first==0) return;
-       
-       while(done==1) {
-               done= 0;
-               
-               toggle++;
-               if(toggle & 1) eed= em->edges.first;
-               else eed= em->edges.last;
-               
-               while(eed) {
-                       v1= eed->v1;
-                       v2= eed->v2;
-                       if(eed->h==0) {
-                               if(v1->f & SELECT) {
-                                       if( (v2->f & SELECT)==0 ) {
-                                               v2->f |= SELECT;
-                                               done= 1;
-                                       }
-                               }
-                               else if(v2->f & SELECT) {
-                                       if( (v1->f & SELECT)==0 ) {
-                                               v1->f |= SELECT;
-                                               done= 1;
-                                       }
-                               }
-                       }
-                       if(toggle & 1) eed= eed->next;
-                       else eed= eed->prev;
-               }
-       }
+#define face_tag(efa)\
+if(efa->v4)    efa->tmp.l=             efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;\
+else           efa->tmp.l=             efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
 
-       /* now use vertex select flag to select rest */
-       EM_select_flush(em);
-       
-//     if (EM_texFaceCheck())
-       BIF_undo_push("Select Connected (All)");
-}
+/* all - 1) use all faces for extending the selection  2) only use the mouse face
+* sel - 1) select  0) deselect 
+* */
 
-void selectconnected_mesh(bContext *C)
+/* legacy warning, this function combines too much :) */
+static int select_linked_limited_invoke(ViewContext *vc, short all, short sel)
 {
-       ViewContext vc;
-       EditVert *eve, *v1, *v2;
-       EditEdge *eed;
+       EditMesh *em= vc->em;
        EditFace *efa;
-       short done=1, sel, toggle=0;
-       int shift= 0; // XXX
-               
-       /* setup view context for argument to callbacks */
-       em_setup_viewcontext(C, &vc);
-       
-       if(vc.em->edges.first==0) return;
+       EditEdge *eed;
+       EditVert *eve;
+       short done=1, change=0;
        
-       if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
-               /* error("Nothing indicated "); */ /* this is mostly annoying, eps with occluded geometry */
-               return;
+       if(em->faces.first==0) return OPERATOR_CANCELLED;
+       
+       /* flag all edges+faces as off*/
+       for(eed= em->edges.first; eed; eed= eed->next)
+               eed->tmp.l=0;
+       
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               efa->tmp.l = 0;
+       }
+       
+       if (all) {
+               // XXX verts?
+               for(eed= em->edges.first; eed; eed= eed->next) {
+                       if(eed->f & SELECT)
+                               eed->tmp.l= 1;
+               }
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       
+                       if (efa->f & SELECT) {
+                               face_tag(efa);
+                       } else {
+                               efa->tmp.l = 0;
+                       }
+               }
+       } 
+       else {
+               if( unified_findnearest(vc, &eve, &eed, &efa) ) {
+                       
+                       if(efa) {
+                               efa->tmp.l = 1;
+                               face_tag(efa);
+                       }
+                       else if(eed)
+                               eed->tmp.l= 1;
+                       else {
+                               for(eed= em->edges.first; eed; eed= eed->next)
+                                       if(eed->v1==eve || eed->v2==eve)
+                                               break;
+                               eed->tmp.l= 1;
+                       }
+               }
+               else
+                       return OPERATOR_FINISHED;
        }
        
-       sel= 1;
-       if(shift) sel=0;
+       while(done==1) {
+               done= 0;
+               /* simple algo - select all faces that have a selected edge
+               * this intern selects the edge, repeat until nothing is left to do */
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       if ((efa->tmp.l == 0) && (!efa->h)) {
+                               if (is_face_tag(efa)) {
+                                       face_tag(efa);
+                                       done= 1;
+                               }
+                       }
+               }
+       }
+       
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               if (efa->tmp.l) {
+                       if (sel) {
+                               if (!(efa->f & SELECT)) {
+                                       EM_select_face(efa, 1);
+                                       change = 1;
+                               }
+                       } else {
+                               if (efa->f & SELECT) {
+                                       EM_select_face(efa, 0);
+                                       change = 1;
+                               }
+                       }
+               }
+       }
+       
+       if (!change)
+               return OPERATOR_CANCELLED;
+       
+       if (!sel) /* make sure de-selecting faces didnt de-select the verts/edges connected to selected faces, this is common with boundries */
+               for(efa= em->faces.first; efa; efa= efa->next)
+                       if (efa->f & SELECT)
+                               EM_select_face(efa, 1);
+       
+       //      if (EM_texFaceCheck())
+       
+       return OPERATOR_FINISHED;
+}
+
+#undef is_edge_delimit_ok
+#undef is_face_tag
+#undef face_tag
+
+static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       Object *obedit= CTX_data_edit_object(C);
+       ViewContext vc;
+       EditVert *eve, *v1, *v2;
+       EditEdge *eed;
+       EditFace *efa;
+       short done=1, toggle=0;
+       int sel= !RNA_boolean_get(op->ptr, "deselect");
+       int limit= RNA_boolean_get(op->ptr, "limit");
+       
+       /* unified_finednearest needs ogl */
+       view3d_operator_needs_opengl(C);
+       
+       /* setup view context for argument to callbacks */
+       em_setup_viewcontext(C, &vc);
+       
+       if(vc.em->edges.first==0) return OPERATOR_CANCELLED;
+       
+       vc.mval[0]= event->mval[0];
+       vc.mval[1]= event->mval[1];
+       
+       /* return warning! */
+       if(limit) {
+               int retval= select_linked_limited_invoke(&vc, 0, sel);
+               WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+               return retval;
+       }
+       
+       if( unified_findnearest(&vc, &eve, &eed, &efa)==0 ) {
+               WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+       
+               return OPERATOR_CANCELLED;
+       }
 
        /* clear test flags */
        for(v1= vc.em->verts.first; v1; v1= v1->next) v1->f1= 0;
@@ -2214,119 +2459,113 @@ void selectconnected_mesh(bContext *C)
        
 //     if (EM_texFaceCheck())
        
-       BIF_undo_push("Select Linked");
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+       return OPERATOR_FINISHED;       
+}
+
+void MESH_OT_select_linked_pick(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select Linked";
+       ot->idname= "MESH_OT_select_linked_pick";
+       
+       /* api callbacks */
+       ot->invoke= select_linked_pick_invoke;
+       ot->poll= ED_operator_editmesh;
        
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
+       RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
 }
 
-/* for use with selectconnected_delimit_mesh only! */
-#define is_edge_delimit_ok(eed) ((eed->tmp.l == 1) && (eed->seam==0))
-#define is_face_tag(efa) is_edge_delimit_ok(efa->e1) || is_edge_delimit_ok(efa->e2) || is_edge_delimit_ok(efa->e3) || (efa->v4 && is_edge_delimit_ok(efa->e4))
 
-#define face_tag(efa)\
-       if(efa->v4)     efa->tmp.l=             efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= efa->e4->tmp.l= 1;\
-       else            efa->tmp.l=             efa->e1->tmp.l= efa->e2->tmp.l= efa->e3->tmp.l= 1;
+/* ************************* */
 
-/* all - 1) use all faces for extending the selection  2) only use the mouse face
- * sel - 1) select  0) deselect 
- * */
-static void selectconnected_delimit_mesh__internal(ViewContext *vc, short all, short sel)
+void selectconnected_mesh_all(EditMesh *em)
 {
-       EditMesh *em= vc->em;
-       EditFace *efa;
+       EditVert *v1,*v2;
        EditEdge *eed;
-       short done=1, change=0;
-       int dist = 75;
-       
-       if(em->faces.first==0) return;
-       
-       /* flag all edges as off*/
-       for(eed= em->edges.first; eed; eed= eed->next)
-               eed->tmp.l=0;
+       short done=1, toggle=0;
        
-       if (all) {
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       if (efa->f & SELECT) {
-                               face_tag(efa);
-                       } else {
-                               efa->tmp.l = 0;
-                       }
-               }
-       } else {
-               EditFace *efa_mouse = findnearestface(vc, &dist);
-               
-               if( !efa_mouse ) {
-                       /* error("Nothing indicated "); */ /* this is mostly annoying, eps with occluded geometry */
-                       return;
-               }
-               
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       efa->tmp.l = 0;
-               }
-               efa_mouse->tmp.l = 1;
-               face_tag(efa_mouse);
-       }
+       if(em->edges.first==0) return;
        
        while(done==1) {
                done= 0;
-               /* simple algo - select all faces that have a selected edge
-                * this intern selects the edge, repeat until nothing is left to do */
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       if ((efa->tmp.l == 0) && (!efa->h)) {
-                               if (is_face_tag(efa)) {
-                                       face_tag(efa);
-                                       done= 1;
-                               }
-                       }
-               }
-       }
-       
-       for(efa= em->faces.first; efa; efa= efa->next) {
-               if (efa->tmp.l) {
-                       if (sel) {
-                               if (!(efa->f & SELECT)) {
-                                       EM_select_face(efa, 1);
-                                       change = 1;
+               
+               toggle++;
+               if(toggle & 1) eed= em->edges.first;
+               else eed= em->edges.last;
+               
+               while(eed) {
+                       v1= eed->v1;
+                       v2= eed->v2;
+                       if(eed->h==0) {
+                               if(v1->f & SELECT) {
+                                       if( (v2->f & SELECT)==0 ) {
+                                               v2->f |= SELECT;
+                                               done= 1;
+                                       }
                                }
-                       } else {
-                               if (efa->f & SELECT) {
-                                       EM_select_face(efa, 0);
-                                       change = 1;
+                               else if(v2->f & SELECT) {
+                                       if( (v1->f & SELECT)==0 ) {
+                                               v1->f |= SELECT;
+                                               done= 1;
+                                       }
                                }
                        }
+                       if(toggle & 1) eed= eed->next;
+                       else eed= eed->prev;
                }
        }
        
-       if (!change)
-               return;
-       
-       if (!sel) /* make sure de-selecting faces didnt de-select the verts/edges connected to selected faces, this is common with boundries */
-               for(efa= em->faces.first; efa; efa= efa->next)
-                       if (efa->f & SELECT)
-                               EM_select_face(efa, 1);
-       
-//     if (EM_texFaceCheck())
-       
-       BIF_undo_push("Select Linked Delimeted");
+       /* now use vertex select flag to select rest */
+       EM_select_flush(em);
        
+       //      if (EM_texFaceCheck())
 }
 
-#undef is_edge_delimit_ok
-#undef is_face_tag
-#undef face_tag
-
-void selectconnected_delimit_mesh(EditMesh *em)
+static int select_linked_exec(bContext *C, wmOperator *op)
 {
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(obedit->data);
+       
+       if( RNA_boolean_get(op->ptr, "limit") ) {
+               ViewContext vc;
+               em_setup_viewcontext(C, &vc);
+               select_linked_limited_invoke(&vc, 1, 1);
+       }
+       else
+               selectconnected_mesh_all(em);
        
-       // XXX selectconnected_delimit_mesh__internal(em, 0, ((G.qual & LR_SHIFTKEY)==0));
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;       
 }
-void selectconnected_delimit_mesh_all(ViewContext *vc)
+
+void MESH_OT_select_linked(wmOperatorType *ot)
 {
-       selectconnected_delimit_mesh__internal(vc, 1, 1);
-}      
+       /* identifiers */
+       ot->name= "Select Linked All";
+       ot->idname= "MESH_OT_select_linked";
        
+       /* api callbacks */
+       ot->exec= select_linked_exec;
+       ot->poll= ED_operator_editmesh;
        
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       RNA_def_boolean(ot->srna, "limit", 0, "Limit by Seams", "");
+}
+
+
+/* ************************* */
+
 /* swap is 0 or 1, if 1 it hides not selected */
-void hide_mesh(EditMesh *em, int swap)
+void EM_hide_mesh(EditMesh *em, int swap)
 {
        EditVert *eve;
        EditEdge *eed;
@@ -2422,15 +2661,43 @@ void hide_mesh(EditMesh *em, int swap)
                }
        }
        
-       G.totedgesel= G.totfacesel= G.totvertsel= 0;
+       em->totedgesel= em->totfacesel= em->totvertsel= 0;
 //     if(EM_texFaceCheck())
 
        //      DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
-       BIF_undo_push("Hide");
 }
 
+static int hide_mesh_exec(bContext *C, wmOperator *op)
+{
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+       
+       EM_hide_mesh(em, RNA_boolean_get(op->ptr, "unselected"));
+               
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;       
+}
+
+void MESH_OT_hide(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Hide Selection";
+       ot->idname= "MESH_OT_hide";
+       
+       /* api callbacks */
+       ot->exec= hide_mesh_exec;
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
+}
 
-void reveal_mesh(EditMesh *em)
+void EM_reveal_mesh(EditMesh *em)
 {
        EditVert *eve;
        EditEdge *eed;
@@ -2464,249 +2731,53 @@ void reveal_mesh(EditMesh *em)
 
 //     if (EM_texFaceCheck())
 //     DAG_object_flush_update(scene, obedit, OB_RECALC_DATA); 
-       BIF_undo_push("Reveal");
 }
 
-void hide_tface_uv(EditMesh *em, int swap)
+static int reveal_mesh_exec(bContext *C, wmOperator *op)
 {
-#if 0
-       /* no space image here */
-       EditFace *efa;
-       MTFace *tface;
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
        
-       if( is_uv_tface_editing_allowed()==0 ) return;
+       EM_reveal_mesh(em);
 
-       /* call the mesh function if we are in mesh sync sel */
-       if (G.sima->flag & SI_SYNC_UVSEL) {
-               hide_mesh(swap);
-               return;
-       }
-       
-       if(swap) {
-               for (efa= em->faces.first; efa; efa= efa->next) {
-                       if(efa->f & SELECT) {
-                               tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                               if (G.sima->flag & SI_SELACTFACE) {
-                                       /* Pretend face mode */
-                                       if ((   (efa->v4==NULL && 
-                                                       (       tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) ==                     (TF_SEL1|TF_SEL2|TF_SEL3) )                      ||
-                                                       (       tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) ==     (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)       ) == 0) {
-                                               
-                                               if (em->selectmode == SCE_SELECT_FACE) {
-                                                       efa->f &= ~SELECT;
-                                                       /* must re-select after */
-                                                       efa->e1->f &= ~SELECT;
-                                                       efa->e2->f &= ~SELECT;
-                                                       efa->e3->f &= ~SELECT;
-                                                       if(efa->e4) efa->e4->f &= ~SELECT;
-                                               } else {
-                                                       EM_select_face(efa, 0);
-                                               }
-                                       }
-                                       tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
-                               } else if (em->selectmode == SCE_SELECT_FACE) {
-                                       if((tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))==0) {
-                                               if(!efa->v4)
-                                                       EM_select_face(efa, 0);
-                                               else if(!(tface->flag & TF_SEL4))
-                                                       EM_select_face(efa, 0);
-                                               tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
-                                       }
-                               } else {
-                                       /* EM_deselect_flush will deselect the face */
-                                       if((tface->flag & TF_SEL1)==0)                          efa->v1->f &= ~SELECT;
-                                       if((tface->flag & TF_SEL2)==0)                          efa->v2->f &= ~SELECT;
-                                       if((tface->flag & TF_SEL3)==0)                          efa->v3->f &= ~SELECT;
-                                       if((efa->v4) && (tface->flag & TF_SEL4)==0)     efa->v4->f &= ~SELECT;                  
-                                       tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
-                               }
-                       }
-               }
-       } else {
-               for (efa= em->faces.first; efa; efa= efa->next) {
-                       if(efa->f & SELECT) {
-                               tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                               if (G.sima->flag & SI_SELACTFACE) {
-                                       if (    (efa->v4==NULL && 
-                                                       (       tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) ==                     (TF_SEL1|TF_SEL2|TF_SEL3) )                      ||
-                                                       (       tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) ==     (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)       ) {
-                                               
-                                               if (em->selectmode == SCE_SELECT_FACE) {
-                                                       efa->f &= ~SELECT;
-                                                       /* must re-select after */
-                                                       efa->e1->f &= ~SELECT;
-                                                       efa->e2->f &= ~SELECT;
-                                                       efa->e3->f &= ~SELECT;
-                                                       if(efa->e4) efa->e4->f &= ~SELECT;
-                                               } else {
-                                                       EM_select_face(efa, 0);
-                                               }
-                                       }
-                                       tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
-                               } else if (em->selectmode == SCE_SELECT_FACE) {
-                                       if(tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
-                                               EM_select_face(efa, 0);
-                                       else if(efa->v4 && tface->flag & TF_SEL4)
-                                               EM_select_face(efa, 0);
-                                       tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
-                               } else {
-                                       /* EM_deselect_flush will deselect the face */
-                                       if(tface->flag & TF_SEL1)                               efa->v1->f &= ~SELECT;
-                                       if(tface->flag & TF_SEL2)                               efa->v2->f &= ~SELECT;
-                                       if(tface->flag & TF_SEL3)                               efa->v3->f &= ~SELECT;
-                                       if((efa->v4) && tface->flag & TF_SEL4)  efa->v4->f &= ~SELECT;
-                                       tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
-                               }
-                       }
-               }
-       }
-       
-       
-       /*deselects too many but ok for now*/
-       if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX)) {
-               EM_deselect_flush(em);
-       }
-       
-       if (em->selectmode==SCE_SELECT_FACE) {
-               /* de-selected all edges from faces that were de-selected.
-                * now make sure all faces that are selected also have selected edges */
-               for (efa= em->faces.first; efa; efa= efa->next) {
-                       if (efa->f & SELECT) {
-                               EM_select_face(efa, 1);
-                       }
-               }
-       }
-       
-       EM_validate_selections();
-       
-       BIF_undo_push("Hide UV");
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 
-// XXX object_tface_flags_changed(OBACT, 0);
-#endif
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;       
 }
 
-void reveal_tface_uv(EditMesh *em)
+void MESH_OT_reveal(wmOperatorType *ot)
 {
-#if 0
-       /* function should move away? */
-       EditFace *efa;
-       MTFace *tface;
-
-       if( is_uv_tface_editing_allowed()==0 ) return;
-       
-       /* call the mesh function if we are in mesh sync sel */
-       if (G.sima->flag & SI_SYNC_UVSEL) {
-               reveal_mesh();
-               return;
-       }
-       
-       if (G.sima->flag & SI_SELACTFACE) {
-               if (em->selectmode == SCE_SELECT_FACE) {
-                       for (efa= em->faces.first; efa; efa= efa->next) {
-                               if (!(efa->h) && !(efa->f & SELECT)) {
-                                       tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                                       EM_select_face(efa, 1);
-                                       tface->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
-                               }
-                       }
-               } else {
-                       /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
-                       if (G.sima->sticky == SI_STICKY_DISABLE) {
-                               for (efa= em->faces.first; efa; efa= efa->next) {
-                                       if (!(efa->h) && !(efa->f & SELECT)) {
-                                               /* All verts must be unselected for the face to be selected in the UV view */
-                                               if ((efa->v1->f&SELECT)==0 && (efa->v2->f&SELECT)==0 && (efa->v3->f&SELECT)==0 && (efa->v4==0 || (efa->v4->f&SELECT)==0)) {
-                                                       tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                                                       tface->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
-                                                       /* Cant use EM_select_face here because it unselects the verts
-                                                        * and we cant tell if the face was totally unselected or not */
-                                                       /*EM_select_face(efa, 1);
-                                                        * 
-                                                        * See Loop with EM_select_face() below... */
-                                                       efa->f |= SELECT;
-                                               }
-                                       }
-                               }
-                       } else {
-                               for (efa= em->faces.first; efa; efa= efa->next) {
-                                       if (!(efa->h) && !(efa->f & SELECT)) {
-                                               tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                                               if ((efa->v1->f & SELECT)==0)                           {tface->flag |= TF_SEL1;}
-                                               if ((efa->v2->f & SELECT)==0)                           {tface->flag |= TF_SEL2;}
-                                               if ((efa->v3->f & SELECT)==0)                           {tface->flag |= TF_SEL3;}
-                                               if ((efa->v4 && (efa->v4->f & SELECT)==0))      {tface->flag |= TF_SEL4;}
-                                               efa->f |= SELECT;
-                                       }
-                               }
-                       }
-                       
-                       /* Select all edges and verts now */
-                       for (efa= em->faces.first; efa; efa= efa->next) {
-                               /* we only selected the face flags, and didnt changes edges or verts, fix this now */
-                               if (!(efa->h) && (efa->f & SELECT)) {
-                                       EM_select_face(efa, 1);
-                               }
-                       }
-                       EM_select_flush(em);
-               }
-       } else if (em->selectmode == SCE_SELECT_FACE) {
-               for (efa= em->faces.first; efa; efa= efa->next) {
-                       if (!(efa->h) && !(efa->f & SELECT)) {
-                               tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                               efa->f |= SELECT;
-                               tface->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
-                       }
-               }
-               
-               /* Select all edges and verts now */
-               for (efa= em->faces.first; efa; efa= efa->next) {
-                       /* we only selected the face flags, and didnt changes edges or verts, fix this now */
-                       if (!(efa->h) && (efa->f & SELECT)) {
-                               EM_select_face(efa, 1);
-                       }
-               }
-               
-       } else {
-               for (efa= em->faces.first; efa; efa= efa->next) {
-                       if (!(efa->h) && !(efa->f & SELECT)) {
-                               tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                               if ((efa->v1->f & SELECT)==0)                           {tface->flag |= TF_SEL1;}
-                               if ((efa->v2->f & SELECT)==0)                           {tface->flag |= TF_SEL2;}
-                               if ((efa->v3->f & SELECT)==0)                           {tface->flag |= TF_SEL3;}
-                               if ((efa->v4 && (efa->v4->f & SELECT)==0))      {tface->flag |= TF_SEL4;}
-                               efa->f |= SELECT;
-                       }
-               }
-               
-               /* Select all edges and verts now */
-               for (efa= em->faces.first; efa; efa= efa->next) {
-                       /* we only selected the face flags, and didnt changes edges or verts, fix this now */
-                       if (!(efa->h) && (efa->f & SELECT)) {
-                               EM_select_face(efa, 1);
-                       }
-               }
-       }
+       /* identifiers */
+       ot->name= "Reveal Hidden";
+       ot->idname= "MESH_OT_reveal";
        
-       BIF_undo_push("Reveal UV");
+       /* api callbacks */
+       ot->exec= reveal_mesh_exec;
+       ot->poll= ED_operator_editmesh;
        
-// XXX object_tface_flags_changed(OBACT, 0);
-#endif
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
-void select_faces_by_numverts(EditMesh *em, int numverts)
+int select_by_number_vertices_exec(bContext *C, wmOperator *op)
 {
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
        EditFace *efa;
+       int numverts= RNA_enum_get(op->ptr, "type");
 
        /* Selects trias/qiads or isolated verts, and edges that do not have 2 neighboring
         * faces
         */
 
        /* for loose vertices/edges, we first select all, loop below will deselect */
-       if(numverts==5)
+       if(numverts==5) {
                EM_set_flag_all(em, SELECT);
+       }
        else if(em->selectmode!=SCE_SELECT_FACE) {
-               error("Only works in face selection mode");
-               return;
+               BKE_report(op->reports, RPT_ERROR, "Only works in face selection mode");
+               return OPERATOR_CANCELLED;
        }
        
        for(efa= em->faces.first; efa; efa= efa->next) {
@@ -2718,42 +2789,60 @@ void select_faces_by_numverts(EditMesh *em, int numverts)
                }
        }
 
-//     if (EM_texFaceCheck())
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
        
-       if (numverts==3)
-               BIF_undo_push("Select Triangles");
-       else if (numverts==4)
-               BIF_undo_push("Select Quads");
-       else
-               BIF_undo_push("Select non-Triangles/Quads");
+       return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_by_number_vertices(wmOperatorType *ot)
+{
+       static const EnumPropertyItem type_items[]= {
+               {3, "TRIANGLES", 0, "Triangles", NULL},
+               {4, "QUADS", 0, "Triangles", NULL},
+               {5, "OTHER", 0, "Other", NULL},
+               {0, NULL, 0, NULL, NULL}};
+
+       /* identifiers */
+       ot->name= "Select by Number of Vertices";
+       ot->idname= "MESH_OT_select_by_number_vertices";
+       
+       /* api callbacks */
+       ot->exec= select_by_number_vertices_exec;
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_enum(ot->srna, "type", type_items, 3, "Type", "Type of elements to select.");
 }
 
-void select_sharp_edges(EditMesh *em)
+static int select_sharp_edges_exec(bContext *C, wmOperator *op)
 {
        /* Find edges that have exactly two neighboring faces,
-        * check the angle between those faces, and if angle is
-        * small enough, select the edge
-        */
+       * check the angle between those faces, and if angle is
+       * small enough, select the edge
+       */
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
        EditEdge *eed;
        EditFace *efa;
        EditFace **efa1;
        EditFace **efa2;
-       intptr_t edgecount = 0, i;
-       static short sharpness = 135;
-       float fsharpness;
-
+       intptr_t edgecount = 0, i = 0;
+       float sharpness, fsharpness;
+       
+       /* 'standard' behaviour - check if selected, then apply relevant selection */
+       
        if(em->selectmode==SCE_SELECT_FACE) {
-               error("Doesn't work in face selection mode");
-               return;
+               BKE_report(op->reports, RPT_ERROR, "Doesn't work in face selection mode");
+               BKE_mesh_end_editmesh(obedit->data, em);
+               return OPERATOR_CANCELLED;
        }
 
-// XXX if(button(&sharpness,0, 180,"Max Angle:")==0) return;
-       /* if faces are at angle 'sharpness', then the face normals
-        * are at angle 180.0 - 'sharpness' (convert to radians too)
-        */
+       sharpness= RNA_float_get(op->ptr, "sharpness");
        fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
 
-       i=0;
        /* count edges, use tmp.l  */
        eed= em->edges.first;
        while(eed) {
@@ -2825,10 +2914,31 @@ void select_sharp_edges(EditMesh *em)
 
 //     if (EM_texFaceCheck())
        
-       BIF_undo_push("Select Sharp Edges");
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); //TODO is this needed ?
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;       
+}
+
+void MESH_OT_edges_select_sharp(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select Sharp Edges";
+       ot->idname= "MESH_OT_edges_select_sharp";
+       
+       /* api callbacks */
+       ot->exec= select_sharp_edges_exec;
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_float(ot->srna, "sharpness", 0.01f, 0.0f, FLT_MAX, "sharpness", "", 0.0f, 180.0f);
 }
 
-void select_linked_flat_faces(EditMesh *em)
+
+static void select_linked_flat_faces(EditMesh *em, wmOperator *op, float sharpness)
 {
        /* Find faces that are linked to selected faces that are 
         * relatively flat (angle between faces is higher than
@@ -2839,18 +2949,13 @@ void select_linked_flat_faces(EditMesh *em)
        EditFace **efa1;
        EditFace **efa2;
        intptr_t edgecount = 0, i, faceselcount=0, faceselcountold=0;
-       static short sharpness = 135;
        float fsharpness;
-
+       
        if(em->selectmode!=SCE_SELECT_FACE) {
-               error("Only works in face selection mode");
+               BKE_report(op->reports, RPT_ERROR, "Only works in face selection mode");
                return;
        }
 
-// XXX if(button(&sharpness,0, 180,"Min Angle:")==0) return;
-       /* if faces are at angle 'sharpness', then the face normals
-        * are at angle 180.0 - 'sharpness' (convert to radians too)
-        */
        fsharpness = ((180.0 - sharpness) * M_PI) / 180.0;
 
        i=0;
@@ -2967,10 +3072,39 @@ void select_linked_flat_faces(EditMesh *em)
 
 //     if (EM_texFaceCheck())
 
-       BIF_undo_push("Select Linked Flat Faces");
 }
 
-void select_non_manifold(EditMesh *em)
+static int select_linked_flat_faces_exec(bContext *C, wmOperator *op)
+{
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+       
+       select_linked_flat_faces(em, op, RNA_float_get(op->ptr, "sharpness"));
+       
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;       
+}
+
+void MESH_OT_faces_select_linked_flat(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select Linked Flat Faces";
+       ot->idname= "MESH_OT_faces_select_linked_flat";
+       
+       /* api callbacks */
+       ot->exec= select_linked_flat_faces_exec;
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_float(ot->srna, "sharpness", 0.0f, 0.0f, FLT_MAX, "sharpness", "", 0.0f, 180.0f);
+}
+
+void select_non_manifold(EditMesh *em, wmOperator *op )
 {
        EditVert *eve;
        EditEdge *eed;
@@ -2981,7 +3115,7 @@ void select_non_manifold(EditMesh *em)
         */
        
        if(em->selectmode==SCE_SELECT_FACE) {
-               error("Doesn't work in face selection mode");
+               BKE_report(op->reports, RPT_ERROR, "Doesn't work in face selection mode");
                return;
        }
 
@@ -3038,10 +3172,36 @@ void select_non_manifold(EditMesh *em)
 
 //     if (EM_texFaceCheck())
 
-       BIF_undo_push("Select Non Manifold");
 }
 
-void selectswap_mesh(EditMesh *em) /* UI level */
+static int select_non_manifold_exec(bContext *C, wmOperator *op)
+{
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+       
+       select_non_manifold(em, op);
+       
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;       
+}
+
+void MESH_OT_select_non_manifold(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select Non Manifold";
+       ot->idname= "MESH_OT_select_non_manifold";
+       
+       /* api callbacks */
+       ot->exec= select_non_manifold_exec;
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
+
+void EM_select_swap(EditMesh *em) /* exported for UV */
 {
        EditVert *eve;
        EditEdge *eed;
@@ -3071,45 +3231,74 @@ void selectswap_mesh(EditMesh *em) /* UI level */
                }
        }
 
-       EM_selectmode_flush(em);
+       EM_selectmode_flush(em);
+       
+//     if (EM_texFaceCheck())
+
+}
+
+static int select_inverse_mesh_exec(bContext *C, wmOperator *op)
+{
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+       
+       EM_select_swap(em);
+       
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;       
+}
+
+void MESH_OT_select_inverse(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select Inverse";
+       ot->idname= "MESH_OT_select_inverse";
        
-//     if (EM_texFaceCheck())
-
-       BIF_undo_push("Select Swap");
+       /* api callbacks */
+       ot->exec= select_inverse_mesh_exec;
+       ot->poll= ED_operator_editmesh;
        
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
-
+       
 /* ******************** (de)select all operator **************** */
 
+void EM_toggle_select_all(EditMesh *em) /* exported for UV */
+{
+       if(EM_nvertices_selected(em))
+               EM_clear_flag_all(em, SELECT);
+       else 
+               EM_set_flag_all(em, SELECT);
+}
+
 static int toggle_select_all_exec(bContext *C, wmOperator *op)
 {
        Object *obedit= CTX_data_edit_object(C);
-       EditMesh *em= ((Mesh *)obedit->data)->edit_mesh;
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
        
-       if( EM_nvertices_selected(em) ) {
-               EM_clear_flag_all(em, SELECT);
-               BIF_undo_push("Deselect All");
-       }
-       else  {
-               EM_set_flag_all(em, SELECT);
-               BIF_undo_push("Select All");
-       }
-               
-//             if (EM_texFaceCheck())
+       EM_toggle_select_all(em);
        
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);     
+       BKE_mesh_end_editmesh(obedit->data, em);
+
        return OPERATOR_FINISHED;
 }
 
-void MESH_OT_de_select_all(wmOperatorType *ot)
+void MESH_OT_select_all_toggle(wmOperatorType *ot)
 {
        /* identifiers */
-       ot->name= "Select or Deselect All";
-       ot->idname= "MESH_OT_de_select_all";
+       ot->name= "Select/Deselect All";
+       ot->idname= "MESH_OT_select_all_toggle";
        
        /* api callbacks */
        ot->exec= toggle_select_all_exec;
        ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
 /* ******************** **************** */
@@ -3153,13 +3342,33 @@ void EM_select_more(EditMesh *em)
        }
 }
 
-void select_more(EditMesh *em)
+static int select_more(bContext *C, wmOperator *op)
 {
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data)) ;
+
        EM_select_more(em);
 
 //     if (EM_texFaceCheck(em))
 
-       BIF_undo_push("Select More");
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;
+}
+
+void MESH_OT_select_more(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select More";
+       ot->idname= "MESH_OT_select_more";
+
+       /* api callbacks */
+       ot->exec= select_more;
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }
 
 void EM_select_less(EditMesh *em)
@@ -3223,23 +3432,40 @@ void EM_select_less(EditMesh *em)
        }
 }
 
-void select_less(EditMesh *em)
+static int select_less(bContext *C, wmOperator *op)
 {
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+
        EM_select_less(em);
-       
-       BIF_undo_push("Select Less");
 
 //     if (EM_texFaceCheck(em))
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;
 }
 
+void MESH_OT_select_less(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select Less";
+       ot->idname= "MESH_OT_select_less";
+
+       /* api callbacks */
+       ot->exec= select_less;
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+}
 
-void selectrandom_mesh(EditMesh *em) /* randomly selects a user-set % of vertices/edges/faces */
+static void selectrandom_mesh(EditMesh *em, float perc) /* randomly selects a user-set % of vertices/edges/faces */
 {
        EditVert *eve;
        EditEdge *eed;
        EditFace *efa;
-       static short randfac = 50;
-
+       float randfac= perc;
        /* Get the percentage of vertices to randomly select as 'randfac' */
 // XXX if(button(&randfac,0, 100,"Percentage:")==0) return;
 
@@ -3248,38 +3474,66 @@ void selectrandom_mesh(EditMesh *em) /* randomly selects a user-set % of vertice
        if(em->selectmode & SCE_SELECT_VERTEX) {
                for(eve= em->verts.first; eve; eve= eve->next) {
                        if(eve->h==0) {
-                               if ( (BLI_frand() * 100) < randfac) 
+                               if (BLI_frand() < randfac) 
                                        eve->f |= SELECT;
                        }
                }
                EM_selectmode_flush(em);
-               BIF_undo_push("Select Random: Vertices");
        }
        else if(em->selectmode & SCE_SELECT_EDGE) {
                for(eed= em->edges.first; eed; eed= eed->next) {
                        if(eed->h==0) {
-                               if ( (BLI_frand() * 100) < randfac) 
+                               if (BLI_frand() < randfac) 
                                        EM_select_edge(eed, 1);
                        }
                }
                EM_selectmode_flush(em);
-               BIF_undo_push("Select Random:Edges");
        }
        else {
                for(efa= em->faces.first; efa; efa= efa->next) {
                        if(efa->h==0) {
-                               if ( (BLI_frand() * 100) < randfac) 
+                               if (BLI_frand() < randfac) 
                                        EM_select_face(efa, 1);
                        }
                }
                
                EM_selectmode_flush(em);
-               BIF_undo_push("Select Random:Faces");
        }
 //     if (EM_texFaceCheck())
 }
 
-void editmesh_select_by_material(EditMesh *em, int index) 
+static int mesh_select_random_exec(bContext *C, wmOperator *op)
+{
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+       
+       selectrandom_mesh(em, RNA_float_get(op->ptr,"percent"));
+               
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+       
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;       
+}
+
+void MESH_OT_select_random(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select Random";
+       ot->idname= "MESH_OT_select_random";
+
+       /* api callbacks */
+       ot->exec= mesh_select_random_exec;
+       ot->invoke= WM_operator_props_popup;
+       ot->poll= ED_operator_editmesh;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_float_percentage(ot->srna, "percent", 0.5f, 0.0f, 1.0f, "Percent", "Percentage of vertices to select randomly.", 0.0001f, 1.0f);
+}
+
+void EM_select_by_material(EditMesh *em, int index) 
 {
        EditFace *efa;
        
@@ -3292,7 +3546,7 @@ void editmesh_select_by_material(EditMesh *em, int index)
        EM_selectmode_flush(em);
 }
 
-void editmesh_deselect_by_material(EditMesh *em, int index) 
+void EM_deselect_by_material(EditMesh *em, int index) 
 {
        EditFace *efa;
        
@@ -3305,54 +3559,86 @@ void editmesh_deselect_by_material(EditMesh *em, int index)
        EM_selectmode_flush(em);
 }
 
-void EM_selectmode_menu(EditMesh *em)
+static void mesh_selection_type(Scene *scene, EditMesh *em, int val)
 {
-       int val, ctrl= 0; // XXX
-       
-//     if(em->selectmode & SCE_SELECT_VERTEX) pupmenu_set_active(1);
-//     else if(em->selectmode & SCE_SELECT_EDGE) pupmenu_set_active(2);
-//     else pupmenu_set_active(3);
-       
-//     val= pupmenu("Select Mode%t|Vertices|Edges|Faces");
-       
-       
        if(val>0) {
-               if(val==1){ 
+               if(val==1) 
                        em->selectmode= SCE_SELECT_VERTEX;
                        EM_selectmode_set(em);
-                       BIF_undo_push("Selectmode Set: Vertex");
-                       }
-               else if(val==2){
-                       if(ctrl) EM_convertsel(em, em->selectmode, SCE_SELECT_EDGE);
+               }
+               else if(val==2) {
+                       //if(ctrl) EM_convertsel(em, em->selectmode, SCE_SELECT_EDGE);
                        em->selectmode= SCE_SELECT_EDGE;
                        EM_selectmode_set(em);
-                       BIF_undo_push("Selectmode Set: Edge");
                }
                
                else{
-                       if((ctrl)) EM_convertsel(em, em->selectmode, SCE_SELECT_FACE);
+                       //if((ctrl)) EM_convertsel(em, em->selectmode, SCE_SELECT_FACE);
                        em->selectmode= SCE_SELECT_FACE;
                        EM_selectmode_set(em);
-                       BIF_undo_push("Selectmode Set: Vertex");
                }
                
+               /* note, em stores selectmode to be able to pass it on everywhere without scene,
+                  this is only until all select modes and toolsettings are settled more */
+               scene->toolsettings->selectmode= em->selectmode;
 //             if (EM_texFaceCheck())
        }
 }
 
+static EnumPropertyItem prop_mesh_edit_types[] = {
+       {1, "VERT", 0, "Vertices", ""},
+       {2, "EDGE", 0, "Edges", ""},
+       {3, "FACE", 0, "Faces", ""},
+       {0, NULL, 0, NULL, NULL}
+};
+
+static int mesh_selection_type_exec(bContext *C, wmOperator *op)
+{              
+       
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+
+       mesh_selection_type(CTX_data_scene(C), em, RNA_enum_get(op->ptr,"type"));
+
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+       
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;
+}
+
+void MESH_OT_selection_type(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Selection Mode";
+       ot->idname= "MESH_OT_selection_type";
+       
+       /* api callbacks */
+       ot->invoke= WM_menu_invoke;
+       ot->exec= mesh_selection_type_exec;
+       
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* props */
+       RNA_def_enum(ot->srna, "type", prop_mesh_edit_types, 0, "Type", "Set the mesh selection type");
+       
+}
 /* ************************* SEAMS AND EDGES **************** */
 
-void editmesh_mark_seam(EditMesh *em, int clear)
+static int editmesh_mark_seam(bContext *C, wmOperator *op)
 {
+       Scene *scene = CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+       Mesh *me= ((Mesh *)obedit->data);
        EditEdge *eed;
+       int clear = RNA_boolean_get(op->ptr, "clear");
        
-// XXX if(multires_level1_test()) return;
-
        /* auto-enable seams drawing */
        if(clear==0) {
-               if(!(G.f & G_DRAWSEAMS)) {
-                       G.f |= G_DRAWSEAMS;
-               }
+               me->drawflag |= ME_DRAWSEAMS;
        }
 
        if(clear) {
@@ -3363,7 +3649,6 @@ void editmesh_mark_seam(EditMesh *em, int clear)
                        }
                        eed= eed->next;
                }
-               BIF_undo_push("Mark Seam");
        }
        else {
                eed= em->edges.first;
@@ -3373,27 +3658,47 @@ void editmesh_mark_seam(EditMesh *em, int clear)
                        }
                        eed= eed->next;
                }
-               BIF_undo_push("Clear Seam");
        }
 
+       BKE_mesh_end_editmesh(obedit->data, em);
+
+       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+       return OPERATOR_FINISHED;
+}
+
+void MESH_OT_mark_seam(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Mark Seam";
+       ot->idname= "MESH_OT_mark_seam";
+       
+       /* api callbacks */
+       ot->exec= editmesh_mark_seam;
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
 }
 
-void editmesh_mark_sharp(EditMesh *em, int set)
+static int editmesh_mark_sharp(bContext *C, wmOperator *op)
 {
+       Scene *scene = CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+       Mesh *me= ((Mesh *)obedit->data);
+       int clear = RNA_boolean_get(op->ptr, "clear");
        EditEdge *eed;
 
-#if 0
        /* auto-enable sharp edge drawing */
-       if(set) {
-               if(!(G.f & G_DRAWSEAMS)) {
-                       G.f |= G_DRAWSEAMS;
-               }
+       if(clear == 0) {
+               me->drawflag |= ME_DRAWSHARP;
        }
-#endif
-
-// XXX if(multires_level1_test()) return;
 
-       if(set) {
+       if(!clear) {
                eed= em->edges.first;
                while(eed) {
                        if(!eed->h && (eed->f & SELECT)) eed->sharp = 1;
@@ -3407,175 +3712,33 @@ void editmesh_mark_sharp(EditMesh *em, int set)
                }
        }
 
-}
-
-void BME_Menu()        {
-       short ret;
-       ret= pupmenu("BME modeller%t|Select Edges of Vert%x1");
-       
-       switch(ret)
-       {
-               case 1:
-               //BME_edges_of_vert();
-               break;
-       }
-}
-
-
+       BKE_mesh_end_editmesh(obedit->data, em);
 
-void Vertex_Menu(EditMesh *em) 
-{
-       short ret;
-       ret= pupmenu("Vertex Specials%t|Remove Doubles%x1|Merge%x2|Smooth %x3|Select Vertex Path%x4|Blend From Shape%x5|Propagate To All Shapes%x6");
-
-       switch(ret)
-       {
-               case 1:
-// XXX                 notice("Removed %d Vertices", removedoublesflag(1, 0, scene->toolsettings->doublimit));
-                       BIF_undo_push("Remove Doubles");
-                       break;
-               case 2: 
-// XXX                 mergemenu(em);
-                       break;
-               case 3:
-// XXX                 vertexsmooth(em);
-                       break;
-               case 4:
-// XXX                 pathselect(em);
-                       BIF_undo_push("Select Vertex Path");
-                       break;
-               case 5: 
-// XXX                 shape_copy_select_from(em);
-                       break;
-               case 6: 
-// XXX                 shape_propagate(em);
-                       break;
-       }
-       /* some items crashed because this is in the original W menu but not here. should really manage this better */
-//     DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-}
-
-
-void Edge_Menu(EditMesh *em) 
-{
-       short ret;
-
-       ret= pupmenu("Edge Specials%t|Mark Seam %x1|Clear Seam %x2|Rotate Edge CW%x3|Rotate Edge CCW%x4|Loopcut%x6|Edge Slide%x5|Edge Loop Select%x7|Edge Ring Select%x8|Loop to Region%x9|Region to Loop%x10|Mark Sharp%x11|Clear Sharp%x12");
+       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 
-       switch(ret)
-       {
-       case 1:
-               editmesh_mark_seam(em, 0);
-               break;
-       case 2:
-               editmesh_mark_seam(em, 1);
-               break;
-       case 3:
-//             edge_rotate_selected(em, 2);
-               break;
-       case 4:
-//             edge_rotate_selected(em, 1);
-               break;
-       case 5:
-//             EdgeSlide(em, 0,0.0);
-  //           BIF_undo_push("EdgeSlide");
-               break;
-       case 6:
-//             CutEdgeloop(em, 1);
-               BIF_undo_push("Loopcut New");
-               break;
-       case 7:
-//             loop_multiselect(em, 0);
-               break;
-       case 8:
-//             loop_multiselect(em, 1);
-               break;
-       case 9:
-//             loop_to_region(em);
-               break;
-       case 10:
-//             region_to_loop(em);
-               break;
-       case 11:
-//             editmesh_mark_sharp(em, 1);
-               BIF_undo_push("Mark Sharp");
-//             DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-               break;
-       case 12: 
-//             editmesh_mark_sharp(em, 0);
-               BIF_undo_push("Clear Sharp");
-//             DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-               break;
-       }
-       /* some items crashed because this is in the original W menu but not here. should really manage this better */
-//     DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+       return OPERATOR_FINISHED;
 }
 
-void Face_Menu(EditMesh *em) 
+void MESH_OT_mark_sharp(wmOperatorType *ot)
 {
-       short ret;
-       ret= pupmenu(
-               "Face Specials%t|Flip Normals%x1|Bevel%x2|Shade Smooth%x3|Shade Flat%x4|"
-               "Triangulate (Ctrl T)%x5|Quads from Triangles (Alt J)%x6|Flip Triangle Edges (Ctrl Shift F)%x7|%l|"
-               "Face Mode Set%x8|Face Mode Clear%x9|%l|"
-               "UV Rotate (Shift - CCW)%x10|UV Mirror (Shift - Switch Axis)%x11|"
-               "Color Rotate (Shift - CCW)%x12|Color Mirror (Shift - Switch Axis)%x13");
-
-       switch(ret)
-       {
-               case 1:
-//                     flip_editnormals(em);
-//                     DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-                       BIF_undo_push("Flip Normals");
-                       break;
-               case 2:
-//                     bevel_menu(em);
-                       break;
-               case 3:
-//                     mesh_set_smooth_faces(em, 1);
-                       break;
-               case 4:
-//                     mesh_set_smooth_faces(em, 0);
-                       break;
-                       
-               case 5: /* Quads to Tris */
-//                     convert_to_triface(em, 0);
-//                     DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-                       break;
-               case 6: /* Tris to Quads */
-//                     join_triangles(em);
-                       break;
-               case 7: /* Flip triangle edges */
-//                     edge_flip(em);
-                       break;
-               case 8:
-//                     mesh_set_face_flags(em, 1);
-                       break;
-               case 9:
-//                     mesh_set_face_flags(em, 0);
-                       break;
-                       
-               /* uv texface options */
-               case 10:
-//                     mesh_rotate_uvs(em);
-                       break;
-               case 11:
-//                     mesh_mirror_uvs(em);
-                       break;
-               case 12:
-//                     mesh_rotate_colors(em);
-                       break;
-               case 13:
-//                     mesh_mirror_colors(em);
-                       break;
-       }
-       /* some items crashed because this is in the original W menu but not here. should really manage this better */
-//     DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+       /* identifiers */
+       ot->name= "Mark Sharp";
+       ot->idname= "MESH_OT_mark_sharp";
+       
+       /* api callbacks */
+       ot->exec= editmesh_mark_sharp;
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       RNA_def_boolean(ot->srna, "clear", 0, "Clear", "");
 }
 
-
 /* **************** NORMALS ************** */
 
+/* XXX value of select is messed up, it means two things */
 void righthandfaces(EditMesh *em, int select)  /* makes faces righthand turning */
 {
        EditEdge *eed, *ed1, *ed2, *ed3, *ed4;
@@ -3787,6 +3950,41 @@ void righthandfaces(EditMesh *em, int select)    /* makes faces righthand turning *
 }
 
 
+static int righthandfaces_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene = CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+       
+       /* 'standard' behaviour - check if selected, then apply relevant selection */
+       
+       // XXX  need other args
+       righthandfaces(em, RNA_boolean_get(op->ptr, "inside"));
+       
+       BKE_mesh_end_editmesh(obedit->data, em);
+
+       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); //TODO is this needed ?
+
+       return OPERATOR_FINISHED;       
+}
+
+void MESH_OT_normals_make_consistent(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Make Normals Consistent";
+       ot->idname= "MESH_OT_normals_make_consistent";
+       
+       /* api callbacks */
+       ot->exec= righthandfaces_exec;
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       RNA_def_boolean(ot->srna, "inside", 0, "Inside", "");
+}
+
 /* ********** ALIGN WITH VIEW **************** */
 
 
@@ -3823,7 +4021,7 @@ static int mface_is_selected(MFace *mf)
         * which would use same as vertices method), then added
         * to interface! Hoera! - zr
         */
-void faceselect_align_view_to_selected(View3D *v3d, Mesh *me, int axis)
+void faceselect_align_view_to_selected(View3D *v3d, RegionView3D *rv3d, Mesh *me, wmOperator *op,  int axis)
 {
        float norm[3];
        int i, totselected = 0;
@@ -3854,9 +4052,9 @@ void faceselect_align_view_to_selected(View3D *v3d, Mesh *me, int axis)
        }
 
        if (totselected == 0)
-               error("No faces selected.");
+               BKE_report(op->reports, RPT_ERROR, "No faces selected.");
        else
-               view3d_align_axis_to_vector(NULL, v3d, axis, norm);
+               view3d_align_axis_to_vector(v3d, rv3d, axis, norm);
 }
 
 /* helper for below, to survive non-uniform scaled objects */
@@ -3880,13 +4078,13 @@ static void face_getnormal_obspace(Object *obedit, EditFace *efa, float *fno)
 }
 
 
-void editmesh_align_view_to_selected(Object *obedit, EditMesh *em, View3D *v3d, int axis)
+void editmesh_align_view_to_selected(Object *obedit, EditMesh *em, wmOperator *op, View3D *v3d, RegionView3D *rv3d, int axis)
 {
        int nselverts= EM_nvertices_selected(em);
        float norm[3]={0.0, 0.0, 0.0}; /* used for storing the mesh normal */
        
        if (nselverts==0) {
-               error("No faces or vertices selected.");
+               BKE_report(op->reports, RPT_ERROR, "No faces or vertices selected.");
        } 
        else if (EM_nfaces_selected(em)) {
                EditFace *efa;
@@ -3901,7 +4099,7 @@ void editmesh_align_view_to_selected(Object *obedit, EditMesh *em, View3D *v3d,
                        }
                }
 
-               view3d_align_axis_to_vector(NULL, v3d, axis, norm);
+               view3d_align_axis_to_vector(v3d, rv3d, axis, norm);
        } 
        else if (nselverts>2) {
                float cent[3];
@@ -3926,7 +4124,7 @@ void editmesh_align_view_to_selected(Object *obedit, EditMesh *em, View3D *v3d,
                }
 
                Mat4Mul3Vecfl(obedit->obmat, norm);
-               view3d_align_axis_to_vector(NULL, v3d, axis, norm);
+               view3d_align_axis_to_vector(v3d, rv3d, axis, norm);
        } 
        else if (nselverts==2) { /* Align view to edge (or 2 verts) */ 
                EditVert *eve, *leve= NULL;
@@ -3943,7 +4141,7 @@ void editmesh_align_view_to_selected(Object *obedit, EditMesh *em, View3D *v3d,
                        }
                }
                Mat4Mul3Vecfl(obedit->obmat, norm);
-               view3d_align_axis_to_vector(NULL, v3d, axis, norm);
+               view3d_align_axis_to_vector(v3d, rv3d, axis, norm);
        } 
        else if (nselverts==1) { /* Align view to vert normal */ 
                EditVert *eve;
@@ -3957,22 +4155,23 @@ void editmesh_align_view_to_selected(Object *obedit, EditMesh *em, View3D *v3d,
                        }
                }
                Mat4Mul3Vecfl(obedit->obmat, norm);
-               view3d_align_axis_to_vector(NULL, v3d, axis, norm);
+               view3d_align_axis_to_vector(v3d, rv3d, axis, norm);
        }
 } 
 
 /* **************** VERTEX DEFORMS *************** */
 
-void vertexsmooth(Object *obedit, EditMesh *em)
+static int smooth_vertex(bContext *C, wmOperator *op)
 {
+       Scene *scene= CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
        EditVert *eve, *eve_mir = NULL;
        EditEdge *eed;
        float *adror, *adr, fac;
        float fvec[3];
        int teller=0;
-       ModifierData *md= obedit->modifiers.first;
-
-       if(em==NULL) return;
+       ModifierData *md;
 
        /* count */
        eve= em->verts.first;
@@ -3980,7 +4179,10 @@ void vertexsmooth(Object *obedit, EditMesh *em)
                if(eve->f & SELECT) teller++;
                eve= eve->next;
        }
-       if(teller==0) return;
+       if(teller==0) {
+               BKE_mesh_end_editmesh(obedit->data, em);
+               return OPERATOR_CANCELLED;
+       }
        
        adr=adror= (float *)MEM_callocN(3*sizeof(float *)*teller, "vertsmooth");
        eve= em->verts.first;
@@ -3997,8 +4199,8 @@ void vertexsmooth(Object *obedit, EditMesh *em)
        /* if there is a mirror modifier with clipping, flag the verts that
         * are within tolerance of the plane(s) of reflection 
         */
-       for (; md; md=md->next) {
-               if (md->type==eModifierType_Mirror) {
+       for(md=obedit->modifiers.first; md; md=md->next) {
+               if(md->type==eModifierType_Mirror) {
                        MirrorModifierData *mmd = (MirrorModifierData*) md;     
                
                        if(mmd->flag & MOD_MIR_CLIPPING) {
@@ -4049,9 +4251,9 @@ void vertexsmooth(Object *obedit, EditMesh *em)
                if(eve->f & SELECT) {
                        if(eve->f1) {
                                
-// XXX                         if (scene->toolsettings->editbutflag & B_MESH_X_MIRROR) {
-//                                     eve_mir= editmesh_get_x_mirror_vert(obedit, em, eve->co);
-//                             }
+                               if (scene->toolsettings->editbutflag & B_MESH_X_MIRROR) {
+                                       eve_mir= editmesh_get_x_mirror_vert(obedit, em, eve->co);
+                               }
                                
                                adr = eve->tmp.p;
                                fac= 0.5/(float)eve->f1;
@@ -4089,9 +4291,42 @@ void vertexsmooth(Object *obedit, EditMesh *em)
 
        recalc_editnormals(em);
 
-//     DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+       BKE_mesh_end_editmesh(obedit->data, em);
+
+       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+       return OPERATOR_FINISHED;
+}
+
+static int smooth_vertex_exec(bContext *C, wmOperator *op)
+{
+       int repeat = RNA_int_get(op->ptr, "repeat");
+       int i;
+
+       if (!repeat) repeat = 1;
+
+       for (i=0; i<repeat; i++) {
+               smooth_vertex(C, op);
+       }
+
+       return OPERATOR_FINISHED;
+}
+
+void MESH_OT_vertices_smooth(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Smooth Vertex";
+       ot->idname= "MESH_OT_vertices_smooth";
+       
+       /* api callbacks */
+       ot->exec= smooth_vertex_exec;
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
-       BIF_undo_push("Vertex Smooth");
+       RNA_def_int(ot->srna, "repeat", 1, 1, 100, "Number of times to smooth the mesh", "", 1, INT_MAX);
 }
 
 void vertexnoise(Object *obedit, EditMesh *em)
@@ -4137,20 +4372,18 @@ void vertexnoise(Object *obedit, EditMesh *em)
        recalc_editnormals(em);
 //     DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 
-       BIF_undo_push("Vertex Noise");
 }
 
-void vertices_to_sphere(Scene *scene, View3D *v3d, Object *obedit, EditMesh *em)
+static void vertices_to_sphere(Scene *scene, View3D *v3d, Object *obedit, EditMesh *em, float perc)
 {
        EditVert *eve;
        float *curs, len, vec[3], cent[3], fac, facm, imat[3][3], bmat[3][3];
        int tot;
-       short perc=100;
        
 // XXX if(button(&perc, 1, 100, "Percentage:")==0) return;
        
-       fac= perc/100.0;
-       facm= 1.0-fac;
+       fac= perc/100.0f;
+       facm= 1.0f-fac;
        
        Mat3CpyMat4(bmat, obedit->obmat);
        Mat3Inv(imat, bmat);
@@ -4196,6 +4429,99 @@ void vertices_to_sphere(Scene *scene, View3D *v3d, Object *obedit, EditMesh *em)
        recalc_editnormals(em);
 //     DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
 
-       BIF_undo_push("To Sphere");
+}
+
+static int vertices_to_sphere_exec(bContext *C, wmOperator *op)
+{
+       Object *obedit= CTX_data_edit_object(C);
+       View3D *v3d = CTX_wm_view3d(C);
+       Scene *scene = CTX_data_scene(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+       
+       vertices_to_sphere(scene, v3d, obedit, em, RNA_float_get(op->ptr,"percent"));
+               
+       BKE_mesh_end_editmesh(obedit->data, em);
+
+       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+       
+       return OPERATOR_FINISHED;       
+}
+
+void MESH_OT_vertices_transform_to_sphere(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Vertices to Sphere";
+       ot->idname= "MESH_OT_vertices_transform_to_sphere";
+       
+       /* api callbacks */
+       ot->exec= vertices_to_sphere_exec;
+       ot->poll= ED_operator_editmesh;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       
+       /* props */
+       RNA_def_float(ot->srna, "percent", 100.0f, 0.0f, 100.0f, "Percent", "DOC_BROKEN", 0.01f, 100.0f);
+}
+
+void flipface(EditMesh *em, EditFace *efa)
+{
+       if(efa->v4) {
+               SWAP(EditVert *, efa->v2, efa->v4);
+               SWAP(EditEdge *, efa->e1, efa->e4);
+               SWAP(EditEdge *, efa->e2, efa->e3);
+               EM_data_interp_from_faces(em, efa, NULL, efa, 0, 3, 2, 1);
+       }
+       else {
+               SWAP(EditVert *, efa->v2, efa->v3);
+               SWAP(EditEdge *, efa->e1, efa->e3);
+               efa->e2->dir= 1-efa->e2->dir;
+               EM_data_interp_from_faces(em, efa, NULL, efa, 0, 2, 1, 3);
+       }
+
+       if(efa->v4) CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, efa->n);
+       else CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
+}
+
+
+static int flip_normals(bContext *C, wmOperator *op)
+{
+       Scene *scene = CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
+       EditFace *efa;
+       
+       efa= em->faces.first;
+       while(efa) {
+               if( efa->f & SELECT ){
+                       flipface(em, efa);
+               }
+               efa= efa->next;
+       }
+       
+       /* update vertex normals too */
+       recalc_editnormals(em);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+
+       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+       return OPERATOR_FINISHED;
+}
+
+void MESH_OT_flip_normals(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Flip Normals";
+       ot->idname= "MESH_OT_flip_normals";
+       
+       /* api callbacks */
+       ot->exec= flip_normals;
+       ot->poll= ED_operator_editmesh;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 }