Fix #19382: crash on uv edit stitch, tweaking limit property in tool area.
[blender-staging.git] / source / blender / editors / uvedit / uvedit_ops.c
index 24b664daa1336ec92f180365d44153f598d4a85c..9216cfb5cdc96bdcf0afff545517a3d162d4a99b 100644 (file)
 #include "BKE_report.h"
 #include "BKE_utildefines.h"
 
-#include "IMB_imbuf_types.h" // XXX remove?
-
-#include "BIF_transform.h"
-
+#include "ED_image.h"
 #include "ED_mesh.h"
 #include "ED_screen.h"
+#include "ED_transform.h"
 
 #include "RNA_access.h"
 #include "RNA_define.h"
 
 #include "uvedit_intern.h"
 
-/* local prototypes */
-static void sel_uvco_inside_radius(SpaceImage *sima, Scene *scene, short sel, EditFace *efa, MTFace *tface, int index, float *offset, float *ell, short select_index);
-void uvedit_selectionCB(SpaceImage *sima, Scene *scene, ARegion *ar, short selecting, Object *obedit, short *mval, float rad); /* used in edit.c */
-void uvface_setsel__internal(bContext *C, SpaceImage *sima, Scene *scene, Object *obedit, short select);
-
 /************************* state testing ************************/
 
-int ED_uvedit_test_silent(Object *obedit)
-{
-       if(obedit->type != OB_MESH)
-               return 0;
-
-       return EM_texFaceCheck(((Mesh*)obedit->data)->edit_mesh);
-}
-
 int ED_uvedit_test(Object *obedit)
 {
-       // XXX if(!obedit)
-       // XXX  error("Enter Edit Mode to perform this action");
+       EditMesh *em;
+       int ret;
+
+       if(!obedit || obedit->type != OB_MESH)
+               return 0;
 
-       return ED_uvedit_test_silent(obedit);
+       em = BKE_mesh_get_editmesh(obedit->data);
+       ret = EM_texFaceCheck(em);
+       BKE_mesh_end_editmesh(obedit->data, em);
+       
+       return ret;
 }
 
 /************************* assign image ************************/
@@ -102,7 +94,7 @@ void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *pre
        EditMesh *em;
        EditFace *efa;
        MTFace *tf;
-       int update;
+       int update= 0;
        
        /* skip assigning these procedural images... */
        if(ima && (ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE))
@@ -112,9 +104,11 @@ void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *pre
        if(!obedit || (obedit->type != OB_MESH))
                return;
 
-       em= ((Mesh*)obedit->data)->edit_mesh;
-       if(!em || !em->faces.first);
+       em= BKE_mesh_get_editmesh(((Mesh*)obedit->data));
+       if(!em || !em->faces.first) {
+               BKE_mesh_end_editmesh(obedit->data, em);
                return;
+       }
        
        /* ensure we have a uv layer */
        if(!CustomData_has_layer(&em->fdata, CD_MTFACE)) {
@@ -131,9 +125,6 @@ void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *pre
                                tf->tpage= ima;
                                tf->mode |= TF_TEX;
                                
-                               if(ima->tpageflag & IMA_TILES) tf->mode |= TF_TILES;
-                               else tf->mode &= ~TF_TILES;
-                               
                                if(ima->id.us==0) id_us_plus(&ima->id);
                                else id_lib_extern(&ima->id);
                        }
@@ -147,64 +138,54 @@ void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *pre
        }
 
        /* and update depdency graph */
-       if(update) {
-               DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-               /* XXX ensure undo, notifiers? */
-       }
+       if(update)
+               DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
 }
 
 /* dotile -    1, set the tile flag (from the space image)
  *                     2, set the tile index for the faces. */
-void ED_uvedit_set_tile(Scene *scene, Object *obedit, Image *ima, int curtile, int dotile)
+void ED_uvedit_set_tile(bContext *C, Scene *scene, Object *obedit, Image *ima, int curtile)
 {
        EditMesh *em;
        EditFace *efa;
        MTFace *tf;
        
        /* verify if we have something to do */
-       if(!ima || !ED_uvedit_test_silent(obedit))
+       if(!ima || !ED_uvedit_test(obedit))
                return;
        
        /* skip assigning these procedural images... */
        if(ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE)
                return;
        
-       em= ((Mesh*)obedit->data)->edit_mesh;
+       em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
 
        for(efa= em->faces.first; efa; efa= efa->next) {
                tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 
-               if(efa->h==0 && efa->f & SELECT) {
-                       if(dotile==1) {
-                               /* set tile flag */
-                               if(ima->tpageflag & IMA_TILES)
-                                       tf->mode |= TF_TILES;
-                               else
-                                       tf->mode &= ~TF_TILES;
-                       }
-                       else if(dotile==2)
-                               tf->tile= curtile; /* set tile index */
-               }
+               if(efa->h==0 && efa->f & SELECT)
+                       tf->tile= curtile; /* set tile index */
        }
 
-       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-       // XXX WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+       BKE_mesh_end_editmesh(obedit->data, em);
 }
 
 /*********************** space conversion *********************/
 
-static void uvedit_pixel_to_float(bContext *C, float *dist, float pixeldist)
+static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
 {
-       ImBuf *ibuf= CTX_data_edit_image_buffer(C);
-       float width, height;
+       int width, height;
 
-       if(ibuf && ibuf->x > 0 && ibuf->y > 0) {
-               width= ibuf->x;
-               height= ibuf->y;
+       if(sima) {
+               ED_space_image_size(sima, &width, &height);
        }
        else {
-               width= 256.0f;
-               height= 256.0f;
+               width= 256;
+               height= 256;
        }
 
        dist[0]= pixeldist/width;
@@ -215,7 +196,9 @@ static void uvedit_pixel_to_float(bContext *C, float *dist, float pixeldist)
 
 int uvedit_face_visible_nolocal(Scene *scene, EditFace *efa)
 {
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION)
+       ToolSettings *ts= scene->toolsettings;
+
+       if(ts->uv_flag & UV_SYNC_SELECTION)
                return (efa->h==0);
        else
                return (efa->h==0 && (efa->f & SELECT));
@@ -223,7 +206,9 @@ int uvedit_face_visible_nolocal(Scene *scene, EditFace *efa)
 
 int uvedit_face_visible(Scene *scene, Image *ima, EditFace *efa, MTFace *tf)
 {
-       if(scene->toolsettings->uv_flag & UV_SHOW_SAME_IMAGE)
+       ToolSettings *ts= scene->toolsettings;
+
+       if(ts->uv_flag & UV_SHOW_SAME_IMAGE)
                return (tf->tpage==ima)? uvedit_face_visible_nolocal(scene, efa): 0;
        else
                return uvedit_face_visible_nolocal(scene, efa);
@@ -231,7 +216,9 @@ int uvedit_face_visible(Scene *scene, Image *ima, EditFace *efa, MTFace *tf)
 
 int uvedit_face_selected(Scene *scene, EditFace *efa, MTFace *tf)
 {
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION)
+       ToolSettings *ts= scene->toolsettings;
+
+       if(ts->uv_flag & UV_SYNC_SELECTION)
                return (efa->f & SELECT);
        else
                return (!(~tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) &&(!efa->v4 || tf->flag & TF_SEL4));
@@ -239,7 +226,9 @@ int uvedit_face_selected(Scene *scene, EditFace *efa, MTFace *tf)
 
 void uvedit_face_select(Scene *scene, EditFace *efa, MTFace *tf)
 {
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION)
+       ToolSettings *ts= scene->toolsettings;
+
+       if(ts->uv_flag & UV_SYNC_SELECTION)
                EM_select_face(efa, 1);
        else
                tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
@@ -247,7 +236,9 @@ void uvedit_face_select(Scene *scene, EditFace *efa, MTFace *tf)
 
 void uvedit_face_deselect(Scene *scene, EditFace *efa, MTFace *tf)
 {
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION)
+       ToolSettings *ts= scene->toolsettings;
+
+       if(ts->uv_flag & UV_SYNC_SELECTION)
                EM_select_face(efa, 0);
        else
                tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
@@ -255,12 +246,13 @@ void uvedit_face_deselect(Scene *scene, EditFace *efa, MTFace *tf)
 
 int uvedit_edge_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
 {
+       ToolSettings *ts= scene->toolsettings;
        int nvert= (efa->v4)? 4: 3;
 
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               if(scene->selectmode == SCE_SELECT_FACE)
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               if(ts->selectmode == SCE_SELECT_FACE)
                        return (efa->f & SELECT);
-               else if(scene->selectmode == SCE_SELECT_EDGE)
+               else if(ts->selectmode == SCE_SELECT_EDGE)
                        return (*(&efa->e1 + i))->f & SELECT;
                else
                        return (((efa->v1 + i)->f & SELECT) && ((efa->v1 + (i+1)%nvert)->f & SELECT));
@@ -271,12 +263,13 @@ int uvedit_edge_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
 
 void uvedit_edge_select(Scene *scene, EditFace *efa, MTFace *tf, int i)
 {
+       ToolSettings *ts= scene->toolsettings;
        int nvert= (efa->v4)? 4: 3;
 
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               if(scene->selectmode == SCE_SELECT_FACE)
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               if(ts->selectmode == SCE_SELECT_FACE)
                        EM_select_face(efa, 1);
-               else if(scene->selectmode == SCE_SELECT_EDGE)
+               else if(ts->selectmode == SCE_SELECT_EDGE)
                        EM_select_edge((*(&efa->e1 + i)), 1);
                else {
                        (efa->v1 + i)->f |= SELECT;
@@ -289,12 +282,13 @@ void uvedit_edge_select(Scene *scene, EditFace *efa, MTFace *tf, int i)
 
 void uvedit_edge_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i)
 {
+       ToolSettings *ts= scene->toolsettings;
        int nvert= (efa->v4)? 4: 3;
 
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               if(scene->selectmode == SCE_SELECT_FACE)
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               if(ts->selectmode == SCE_SELECT_FACE)
                        EM_select_face(efa, 0);
-               else if(scene->selectmode == SCE_SELECT_EDGE)
+               else if(ts->selectmode == SCE_SELECT_EDGE)
                        EM_select_edge((*(&efa->e1 + i)), 0);
                else {
                        (efa->v1 + i)->f &= ~SELECT;
@@ -307,8 +301,10 @@ void uvedit_edge_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i)
 
 int uvedit_uv_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
 {
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               if(scene->selectmode == SCE_SELECT_FACE)
+       ToolSettings *ts= scene->toolsettings;
+
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               if(ts->selectmode == SCE_SELECT_FACE)
                        return (efa->f & SELECT);
                else
                        return (*(&efa->v1 + i))->f & SELECT;
@@ -319,8 +315,10 @@ int uvedit_uv_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
 
 void uvedit_uv_select(Scene *scene, EditFace *efa, MTFace *tf, int i)
 {
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               if(scene->selectmode == SCE_SELECT_FACE)
+       ToolSettings *ts= scene->toolsettings;
+
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               if(ts->selectmode == SCE_SELECT_FACE)
                        EM_select_face(efa, 1);
                else
                        (*(&efa->v1 + i))->f |= SELECT;
@@ -331,8 +329,10 @@ void uvedit_uv_select(Scene *scene, EditFace *efa, MTFace *tf, int i)
 
 void uvedit_uv_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i)
 {
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               if(scene->selectmode == SCE_SELECT_FACE)
+       ToolSettings *ts= scene->toolsettings;
+
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               if(ts->selectmode == SCE_SELECT_FACE)
                        EM_select_face(efa, 0);
                else
                        (*(&efa->v1 + i))->f &= ~SELECT;
@@ -380,7 +380,7 @@ void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy)
 
 int ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float *min, float *max)
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        EditFace *efa;
        MTFace *tf;
        int sel;
@@ -397,13 +397,14 @@ int ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float *min, float
                        if(efa->v4 && (uvedit_uv_selected(scene, efa, tf, 3)))  { DO_MINMAX2(tf->uv[3], min, max); sel = 1; }
                }
        }
-
+       
+       BKE_mesh_end_editmesh(obedit->data, em);
        return sel;
 }
 
 int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent, int mode)
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        EditFace *efa;
        MTFace *tf;
        float min[2], max[2];
@@ -431,10 +432,12 @@ int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent, int mod
        if(change) {
                cent[0]= (min[0]+max[0])/2.0;
                cent[1]= (min[1]+max[1])/2.0;
-
+               
+               BKE_mesh_end_editmesh(obedit->data, em);
                return 1;
        }
 
+       BKE_mesh_end_editmesh(obedit->data, em);
        return 0;
 }
 
@@ -593,7 +596,7 @@ static void find_nearest_uv_vert(Scene *scene, Image *ima, EditMesh *em, float c
 
 int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, float co[2], float uv[2])
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        EditFace *efa;
        MTFace *tf;
        float mindist, dist;
@@ -623,6 +626,7 @@ int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, float co[2],
                }
        }
 
+       BKE_mesh_end_editmesh(obedit->data, em);
        return found;
 }
 
@@ -944,74 +948,8 @@ static void select_linked(Scene *scene, Image *ima, EditMesh *em, float limit[2]
        EM_free_uv_vert_map(vmap);
 }
 
-/* ******************** mirror operator **************** */
-
-/* XXX */
-#if 0
-       short mode= 0;
-       mode= pupmenu("Mirror%t|X Axis%x1|Y Axis%x2|");
-#endif
-
-static int mirror_exec(bContext *C, wmOperator *op)
-{
-       float mat[3][3];
-       int axis;
-       
-       Mat3One(mat);
-       axis= RNA_enum_get(op->ptr, "axis");
-
-       if(axis == 'x') {
-               /* XXX initTransform(TFM_MIRROR, CTX_NO_PET|CTX_AUTOCONFIRM);
-               BIF_setSingleAxisConstraint(mat[0], " on X axis");
-               Transform(); */
-       }
-       else {
-               /* XXX initTransform(TFM_MIRROR, CTX_NO_PET|CTX_AUTOCONFIRM);
-               BIF_setSingleAxisConstraint(mat[1], " on Y axis");
-               Transform(); */
-       }
-
-       return OPERATOR_FINISHED;
-}
-
-void UV_OT_mirror(wmOperatorType *ot)
-{
-       static EnumPropertyItem axis_items[] = {
-               {'x', "MIRROR_X", "Mirror X", "Mirror UVs over X axis."},
-               {'y', "MIRROR_Y", "Mirror Y", "Mirror UVs over Y axis."},
-               {0, NULL, NULL, NULL}};
-
-       /* identifiers */
-       ot->name= "Mirror";
-       ot->idname= "UV_OT_mirror";
-       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
-       
-       /* api callbacks */
-       ot->exec= mirror_exec;
-       ot->poll= ED_operator_uvedit;
-
-       /* properties */
-       RNA_def_enum(ot->srna, "axis", axis_items, 'x', "Axis", "Axis to mirror UV locations over.");
-}
-
 /* ******************** align operator **************** */
 
-/* XXX */
-#if 0
-void weld_align_menu_tface_uv(bContext *C)
-{
-       short mode= 0;
-
-       mode= pupmenu("Weld/Align%t|Weld%x1|Align Auto%x2|Align X%x3|Align Y%x4");
-
-       if(mode==-1) return;
-       if(mode==1) weld_align_uv(C, 'w');
-       else if(mode==2) weld_align_uv(C, 'a');
-       else if(mode==3) weld_align_uv(C, 'x');
-       else if(mode==4) weld_align_uv(C, 'y');
-}
-#endif
-
 static void weld_align_uv(bContext *C, int tool)
 {
        Scene *scene;
@@ -1024,7 +962,7 @@ static void weld_align_uv(bContext *C, int tool)
        
        scene= CTX_data_scene(C);
        obedit= CTX_data_edit_object(C);
-       em= ((Mesh*)obedit->data)->edit_mesh;
+       em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        ima= CTX_data_edit_image(C);
 
        INIT_MINMAX2(min, max);
@@ -1082,8 +1020,10 @@ static void weld_align_uv(bContext *C, int tool)
                }
        }
 
-       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); // XXX
+       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
 }
 
 static int align_exec(bContext *C, wmOperator *op)
@@ -1096,15 +1036,15 @@ static int align_exec(bContext *C, wmOperator *op)
 void UV_OT_align(wmOperatorType *ot)
 {
        static EnumPropertyItem axis_items[] = {
-               {'a', "ALIGN_AUTO", "Align Auto", "Automatically choose the axis on which there is most alignment already."},
-               {'x', "ALIGN_X", "Align X", "Align UVs on X axis."},
-               {'y', "ALIGN_Y", "Align Y", "Align UVs on Y axis."},
-               {0, NULL, NULL, NULL}};
+               {'a', "ALIGN_AUTO", 0, "Align Auto", "Automatically choose the axis on which there is most alignment already."},
+               {'x', "ALIGN_X", 0, "Align X", "Align UVs on X axis."},
+               {'y', "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis."},
+               {0, NULL, 0, NULL, NULL}};
 
        /* identifiers */
        ot->name= "Align";
        ot->idname= "UV_OT_align";
-       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* api callbacks */
        ot->exec= align_exec;
@@ -1128,7 +1068,7 @@ void UV_OT_weld(wmOperatorType *ot)
        /* identifiers */
        ot->name= "Weld";
        ot->idname= "UV_OT_weld";
-       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* api callbacks */
        ot->exec= weld_exec;
@@ -1145,6 +1085,7 @@ typedef struct UVVertAverage {
 
 static int stitch_exec(bContext *C, wmOperator *op)
 {
+       SpaceImage *sima;
        Scene *scene;
        Object *obedit;
        EditMesh *em;
@@ -1153,25 +1094,28 @@ static int stitch_exec(bContext *C, wmOperator *op)
        Image *ima;
        MTFace *tf;
        
+       sima= CTX_wm_space_image(C);
        scene= CTX_data_scene(C);
        obedit= CTX_data_edit_object(C);
-       em= ((Mesh*)obedit->data)->edit_mesh;
+       em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        ima= CTX_data_edit_image(C);
        
        if(RNA_boolean_get(op->ptr, "use_limit")) {
                UvVertMap *vmap;
                UvMapVert *vlist, *iterv;
-               float newuv[2], limit[2], pixels;
+               float newuv[2], limit[2];
                int a, vtot;
 
-               pixels= RNA_float_get(op->ptr, "limit");
-               uvedit_pixel_to_float(C, limit, pixels);
+               limit[0]= RNA_float_get(op->ptr, "limit");
+               limit[1]= limit[0];
 
                EM_init_index_arrays(em, 0, 0, 1);
                vmap= EM_make_uv_vert_map(em, 1, 0, limit);
 
-               if(vmap == NULL)
+               if(vmap == NULL) {
+                       BKE_mesh_end_editmesh(obedit->data, em);
                        return OPERATOR_CANCELLED;
+               }
 
                for(a=0, eve= em->verts.first; eve; a++, eve= eve->next) {
                        vlist= EM_get_uv_map_vert(vmap, a);
@@ -1297,9 +1241,10 @@ static int stitch_exec(bContext *C, wmOperator *op)
                MEM_freeN(uv_average);
        }
 
-       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); // XXX
+       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
+       BKE_mesh_end_editmesh(obedit->data, em);
        return OPERATOR_FINISHED;
 }
 
@@ -1308,7 +1253,7 @@ void UV_OT_stitch(wmOperatorType *ot)
        /* identifiers */
        ot->name= "Stitch";
        ot->idname= "UV_OT_stitch";
-       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* api callbacks */
        ot->exec= stitch_exec;
@@ -1316,7 +1261,7 @@ void UV_OT_stitch(wmOperatorType *ot)
 
        /* properties */
        RNA_def_boolean(ot->srna, "use_limit", 1, "Use Limit", "Stitch UVs within a specified limit distance.");
-       RNA_def_float(ot->srna, "limit", 20.0, 0.0f, FLT_MAX, "Limit", "Limit distance in image pixels.", -FLT_MAX, FLT_MAX);
+       RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit", "Limit distance in normalized coordinates.", -FLT_MAX, FLT_MAX);
 }
 
 /* ******************** (de)select all operator **************** */
@@ -1324,6 +1269,7 @@ void UV_OT_stitch(wmOperatorType *ot)
 static int select_inverse_exec(bContext *C, wmOperator *op)
 {
        Scene *scene;
+       ToolSettings *ts;
        Object *obedit;
        EditMesh *em;
        EditFace *efa;
@@ -1331,12 +1277,13 @@ static int select_inverse_exec(bContext *C, wmOperator *op)
        MTFace *tf;
        
        scene= CTX_data_scene(C);
+       ts= CTX_data_tool_settings(C);
        obedit= CTX_data_edit_object(C);
-       em= ((Mesh*)obedit->data)->edit_mesh;
+       em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        ima= CTX_data_edit_image(C);
 
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               // XXX selectswap_mesh();
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               EM_select_swap(em);
        }
        else {
                for(efa= em->faces.first; efa; efa= efa->next) {
@@ -1351,17 +1298,18 @@ static int select_inverse_exec(bContext *C, wmOperator *op)
                }
        }
 
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
+       BKE_mesh_end_editmesh(obedit->data, em);
        return OPERATOR_FINISHED;
 }
 
-void UV_OT_select_invert(wmOperatorType *ot)
+void UV_OT_select_inverse(wmOperatorType *ot)
 {
        /* identifiers */
-       ot->name= "Select Invert";
-       ot->idname= "UV_OT_select_invert";
-       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       ot->name= "Select Inverse";
+       ot->idname= "UV_OT_select_inverse";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* api callbacks */
        ot->exec= select_inverse_exec;
@@ -1373,6 +1321,7 @@ void UV_OT_select_invert(wmOperatorType *ot)
 static int de_select_all_exec(bContext *C, wmOperator *op)
 {
        Scene *scene;
+       ToolSettings *ts;
        Object *obedit;
        EditMesh *em;
        EditFace *efa;
@@ -1381,12 +1330,13 @@ static int de_select_all_exec(bContext *C, wmOperator *op)
        int sel;
        
        scene= CTX_data_scene(C);
+       ts= CTX_data_tool_settings(C);
        obedit= CTX_data_edit_object(C);
-       em= ((Mesh*)obedit->data)->edit_mesh;
+       em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        ima= CTX_data_edit_image(C);
        
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               // XXX deselectall_mesh();
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               EM_toggle_select_all(em);
        }
        else {
                sel= 0;
@@ -1418,17 +1368,18 @@ static int de_select_all_exec(bContext *C, wmOperator *op)
                }
        }
 
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
 
+       BKE_mesh_end_editmesh(obedit->data, em);
        return OPERATOR_FINISHED;
 }
 
-void UV_OT_de_select_all(wmOperatorType *ot)
+void UV_OT_select_all_toggle(wmOperatorType *ot)
 {
        /* identifiers */
-       ot->name= "Select/Deselect All";
-       ot->idname= "UV_OT_de_select_all";
-       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       ot->name= "Select or Deselect All";
+       ot->idname= "UV_OT_select_all_toggle";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* api callbacks */
        ot->exec= de_select_all_exec;
@@ -1462,11 +1413,12 @@ static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], floa
 
 static int mouse_select(bContext *C, float co[2], int extend, int loop)
 {
-       SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
+       SpaceImage *sima= CTX_wm_space_image(C);
        Scene *scene= CTX_data_scene(C);
+       ToolSettings *ts= CTX_data_tool_settings(C);
        Object *obedit= CTX_data_edit_object(C);
        Image *ima= CTX_data_edit_image(C);
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        EditFace *efa;
        MTFace *tf;
        NearestHit hit;
@@ -1474,16 +1426,16 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
        int flush = 0; /* 0 == dont flush, 1 == sel, -1 == desel;  only use when selection sync is enabled */
        float limit[2], *hituv[4], penalty[2];
        
-       uvedit_pixel_to_float(C, limit, 0.05f);
-       uvedit_pixel_to_float(C, penalty, 5.0f);
+       uvedit_pixel_to_float(sima, limit, 0.05f);
+       uvedit_pixel_to_float(sima, penalty, 5.0f);
 
        /* retrieve operation mode */
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
                sync= 1;
 
-               if(scene->selectmode & SCE_SELECT_FACE)
+               if(ts->selectmode & SCE_SELECT_FACE)
                        selectmode= UV_SELECT_FACE;
-               else if(scene->selectmode & SCE_SELECT_EDGE)
+               else if(ts->selectmode & SCE_SELECT_EDGE)
                        selectmode= UV_SELECT_EDGE;
                else
                        selectmode= UV_SELECT_VERTEX;
@@ -1492,25 +1444,26 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
        }
        else {
                sync= 0;
-               selectmode= scene->toolsettings->uv_selectmode;
-               sticky= sima->sticky;
-
-               /* XXX if(sticky == SI_STICKY_VERTEX && (G.qual & LR_CTRLKEY))
-                       sticky= SI_STICKY_DISABLE;*/
+               selectmode= ts->uv_selectmode;
+               sticky= (sima)? sima->sticky: 1;
        }
 
        /* find nearest element */
        if(loop) {
                /* find edge */
                find_nearest_uv_edge(scene, ima, em, co, &hit);
-               if(hit.efa == NULL)
+               if(hit.efa == NULL) {
+                       BKE_mesh_end_editmesh(obedit->data, em);
                        return OPERATOR_CANCELLED;
+               }
        }
        else if(selectmode == UV_SELECT_VERTEX) {
                /* find vertex */
                find_nearest_uv_vert(scene, ima, em, co, penalty, &hit);
-               if(hit.efa == NULL)
+               if(hit.efa == NULL) {
+                       BKE_mesh_end_editmesh(obedit->data, em);
                        return OPERATOR_CANCELLED;
+               }
 
                /* mark 1 vertex as being hit */
                for(i=0; i<4; i++)
@@ -1522,8 +1475,10 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
        else if(selectmode == UV_SELECT_EDGE) {
                /* find edge */
                find_nearest_uv_edge(scene, ima, em, co, &hit);
-               if(hit.efa == NULL)
+               if(hit.efa == NULL) {
+                       BKE_mesh_end_editmesh(obedit->data, em);
                        return OPERATOR_CANCELLED;
+               }
 
                /* mark 2 edge vertices as being hit */
                for(i=0; i<4; i++)
@@ -1539,8 +1494,10 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
        else if(selectmode == UV_SELECT_FACE) {
                /* find face */
                find_nearest_uv_face(scene, ima, em, co, &hit);
-               if(hit.efa == NULL)
+               if(hit.efa == NULL) {
+                       BKE_mesh_end_editmesh(obedit->data, em);
                        return OPERATOR_CANCELLED;
+               }
                
                /* make active */
                EM_set_actFace(em, hit.efa);
@@ -1559,11 +1516,15 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
        else if(selectmode == UV_SELECT_ISLAND) {
                find_nearest_uv_vert(scene, ima, em, co, NULL, &hit);
 
-               if(hit.efa==NULL)
+               if(hit.efa==NULL) {
+                       BKE_mesh_end_editmesh(obedit->data, em);
                        return OPERATOR_CANCELLED;
+               }
        }
-       else
+       else {
+               BKE_mesh_end_editmesh(obedit->data, em);
                return OPERATOR_CANCELLED;
+       }
 
        /* do selection */
        if(loop) {
@@ -1705,19 +1666,16 @@ static int mouse_select(bContext *C, float co[2], int extend, int loop)
        
        if(sync) {
                /* flush for mesh selection */
-               if(scene->selectmode != SCE_SELECT_FACE) {
+               if(ts->selectmode != SCE_SELECT_FACE) {
                        if(flush==1)            EM_select_flush(em);
                        else if(flush==-1)      EM_deselect_flush(em);
                }
        }
        
-       // XXX force_draw(1);
-       // XXX BIF_undo_push("Select UV");
-       // XXX rightmouse_transform();
-
-       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
-
+       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+       
+       BKE_mesh_end_editmesh(obedit->data, em);
        return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
 }
 
@@ -1753,7 +1711,7 @@ void UV_OT_select(wmOperatorType *ot)
        /* identifiers */
        ot->name= "Select";
        ot->idname= "UV_OT_select";
-       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* api callbacks */
        ot->exec= select_exec;
@@ -1769,7 +1727,7 @@ void UV_OT_select(wmOperatorType *ot)
 
 /* ******************** loop select operator **************** */
 
-static int loop_select_exec(bContext *C, wmOperator *op)
+static int select_loop_exec(bContext *C, wmOperator *op)
 {
        float co[2];
        int extend, loop;
@@ -1781,7 +1739,7 @@ static int loop_select_exec(bContext *C, wmOperator *op)
        return mouse_select(C, co, extend, loop);
 }
 
-static int loop_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+static int select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
 {
        ARegion *ar= CTX_wm_region(C);
        float co[2];
@@ -1793,19 +1751,19 @@ static int loop_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
        UI_view2d_region_to_view(&ar->v2d, x, y, &co[0], &co[1]);
        RNA_float_set_array(op->ptr, "location", co);
 
-       return loop_select_exec(C, op);
+       return select_loop_exec(C, op);
 }
 
-void UV_OT_loop_select(wmOperatorType *ot)
+void UV_OT_select_loop(wmOperatorType *ot)
 {
        /* identifiers */
        ot->name= "Loop Select";
-       ot->idname= "UV_OT_loop_select";
-       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       ot->idname= "UV_OT_select_loop";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* api callbacks */
-       ot->exec= loop_select_exec;
-       ot->invoke= loop_select_invoke;
+       ot->exec= select_loop_exec;
+       ot->invoke= select_loop_invoke;
        ot->poll= ED_operator_uvedit;
 
        /* properties */
@@ -1819,25 +1777,29 @@ void UV_OT_loop_select(wmOperatorType *ot)
 
 static int select_linked_exec(bContext *C, wmOperator *op)
 {
+       SpaceImage *sima= CTX_wm_space_image(C);
        Scene *scene= CTX_data_scene(C);
+       ToolSettings *ts= CTX_data_tool_settings(C);
        Object *obedit= CTX_data_edit_object(C);
        Image *ima= CTX_data_edit_image(C);
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        float limit[2];
        int extend;
 
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
                BKE_report(op->reports, RPT_ERROR, "Can't select linked when sync selection is enabled.");
+               BKE_mesh_end_editmesh(obedit->data, em);
                return OPERATOR_CANCELLED;
        }
 
        extend= RNA_boolean_get(op->ptr, "extend");
-       uvedit_pixel_to_float(C, limit, 0.05f);
+       uvedit_pixel_to_float(sima, limit, 0.05f);
        select_linked(scene, ima, em, limit, NULL, extend);
 
-       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
 
+       BKE_mesh_end_editmesh(obedit->data, em);
        return OPERATOR_FINISHED;
 }
 
@@ -1846,7 +1808,7 @@ void UV_OT_select_linked(wmOperatorType *ot)
        /* identifiers */
        ot->name= "Select Linked";
        ot->idname= "UV_OT_select_linked";
-       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* api callbacks */
        ot->exec= select_linked_exec;
@@ -1862,14 +1824,16 @@ void UV_OT_select_linked(wmOperatorType *ot)
 static int unlink_selection_exec(bContext *C, wmOperator *op)
 {
        Scene *scene= CTX_data_scene(C);
+       ToolSettings *ts= CTX_data_tool_settings(C);
        Object *obedit= CTX_data_edit_object(C);
        Image *ima= CTX_data_edit_image(C);
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        EditFace *efa;
        MTFace *tf;
 
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
                BKE_report(op->reports, RPT_ERROR, "Can't unlink selection when sync selection is enabled.");
+               BKE_mesh_end_editmesh(obedit->data, em);
                return OPERATOR_CANCELLED;
        }
        
@@ -1888,9 +1852,10 @@ static int unlink_selection_exec(bContext *C, wmOperator *op)
                }
        }
        
-       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
 
+       BKE_mesh_end_editmesh(obedit->data, em);
        return OPERATOR_FINISHED;
 }
 
@@ -1899,7 +1864,7 @@ void UV_OT_unlink_selection(wmOperatorType *ot)
        /* identifiers */
        ot->name= "Unlink Selection";
        ot->idname= "UV_OT_unlink_selection";
-       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* api callbacks */
        ot->exec= unlink_selection_exec;
@@ -1908,176 +1873,521 @@ void UV_OT_unlink_selection(wmOperatorType *ot)
 
 /* ******************** border select operator **************** */
 
-void borderselect_sima(bContext *C, SpaceImage *sima, Scene *scene, Image *ima, Object *obedit, short whichuvs)
+/* This function sets the selection on tagged faces, need because settings the
+ * selection a face is done in a number of places but it also needs to respect
+ * the sticky modes for the UV verts, so dealing with the sticky modes is best
+ * done in a seperate function.
+ * 
+ * De-selects faces that have been tagged on efa->tmp.l.  */
+
+static void uv_faces_do_sticky(bContext *C, SpaceImage *sima, Scene *scene, Object *obedit, short select)
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       /* Selecting UV Faces with some modes requires us to change 
+        * the selection in other faces (depending on the sticky mode).
+        * 
+        * This only needs to be done when the Mesh is not used for
+        * selection (so for sticky modes, vertex or location based). */
+       
+       ToolSettings *ts= CTX_data_tool_settings(C);
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        EditFace *efa;
-       MTFace *tface;
-       rcti rect;
-       rctf rectf;
-       int val, ok = 1;
-       short mval[2], select;
-
-       if(!ED_uvedit_test(obedit)) return;
-
-       val= 0; // XXX get_border(&rect, 3);
-       select = 0; // XXX (val==LEFTMOUSE) ? 1 : 0; 
+       MTFace *tf;
+       int nverts, i;
        
-       if(val) {
-               mval[0]= rect.xmin;
-               mval[1]= rect.ymin;
-               // XXX areamouseco_to_ipoco(G.v2d, mval, &rectf.xmin, &rectf.ymin);
-               mval[0]= rect.xmax;
-               mval[1]= rect.ymax;
-               // XXX areamouseco_to_ipoco(G.v2d, mval, &rectf.xmax, &rectf.ymax);
+       if((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_VERTEX) {
+               /* Tag all verts as untouched, then touch the ones that have a face center
+                * in the loop and select all MTFace UV's that use a touched vert. */
+               EditVert *eve;
                
-               if(0) { // XXX draw_uvs_face_check() && whichuvs != UV_SELECT_PINNED) {
-                       float cent[2];
-                       ok = 0;
-                       for(efa= em->faces.first; efa; efa= efa->next) {
-                               /* assume not touched */
-                               efa->tmp.l = 0;
-                               tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                               if(uvedit_face_visible(scene, ima, efa, tface)) {
-                                       uv_center(tface->uv, cent, efa->v4 != NULL);
-                                       if(BLI_in_rctf(&rectf, cent[0], cent[1])) {
-                                               efa->tmp.l = ok = 1;
-                                       }
+               for(eve= em->verts.first; eve; eve= eve->next)
+                       eve->tmp.l = 0;
+               
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       if(efa->tmp.l) {
+                               if(efa->v4)
+                                       efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= efa->v4->tmp.l=1;
+                               else
+                                       efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= 1;
+                       }
+               }
+
+               /* now select tagged verts */
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);               
+                       nverts= efa->v4? 4: 3;
+                       for(i=0; i<nverts; i++) {
+                               if((*(&efa->v1 + i))->tmp.l) {
+                                       if(select)
+                                               uvedit_uv_select(scene, efa, tf, i);
+                                       else
+                                               uvedit_uv_deselect(scene, efa, tf, i);
                                }
                        }
-                       /* (de)selects all tagged faces and deals with sticky modes */
-                       if(ok)
-                               uvface_setsel__internal(C, sima, scene, obedit, select);
                }
-               else {
-                       for(efa= em->faces.first; efa; efa= efa->next) {
-                               tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                               if(uvedit_face_visible(scene, ima, efa, tface)) {
-                                       if(whichuvs == UV_SELECT_ALL || (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) ) {
-                                               /* UV_SYNC_SELECTION - cant do pinned selection */
-                                               if(BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
-                                                       if(select)      uvedit_uv_select(scene, efa, tface, 0);
-                                                       else            uvedit_uv_deselect(scene, efa, tface, 0);
-                                               }
-                                               if(BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
-                                                       if(select)      uvedit_uv_select(scene, efa, tface, 1);
-                                                       else            uvedit_uv_deselect(scene, efa, tface, 1);
-                                               }
-                                               if(BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
-                                                       if(select)      uvedit_uv_select(scene, efa, tface, 2);
-                                                       else            uvedit_uv_deselect(scene, efa, tface, 2);
-                                               }
-                                               if(efa->v4 && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
-                                                       if(select)      uvedit_uv_select(scene, efa, tface, 3);
-                                                       else            uvedit_uv_deselect(scene, efa, tface, 3);
-                                               }
-                                       } else if(whichuvs == UV_SELECT_PINNED) {
-                                               if((tface->unwrap & TF_PIN1) && 
-                                                       BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
-                                                       
-                                                       if(select)      uvedit_uv_select(scene, efa, tface, 0);
-                                                       else            uvedit_uv_deselect(scene, efa, tface, 0);
-                                               }
-                                               if((tface->unwrap & TF_PIN2) && 
-                                                       BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
-                                                       
-                                                       if(select)      uvedit_uv_select(scene, efa, tface, 1);
-                                                       else            uvedit_uv_deselect(scene, efa, tface, 1);
-                                               }
-                                               if((tface->unwrap & TF_PIN3) && 
-                                                       BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
+       }
+       else if((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_LOC) {
+               EditFace *efa_vlist;
+               MTFace *tf_vlist;
+               UvMapVert *start_vlist=NULL, *vlist_iter;
+               struct UvVertMap *vmap;
+               float limit[2];
+               int efa_index;
+               //EditVert *eve; /* removed vert counting for now */ 
+               //int a;
+               
+               uvedit_pixel_to_float(sima, limit, 0.05);
+               
+               EM_init_index_arrays(em, 0, 0, 1);
+               vmap= EM_make_uv_vert_map(em, 0, 0, limit);
+               
+               /* verts are numbered above in make_uv_vert_map_EM, make sure this stays true! */
+               /*for(a=0, eve= em->verts.first; eve; a++, eve= eve->next)
+                       eve->tmp.l = a; */
+               
+               if(vmap == NULL) {
+                       BKE_mesh_end_editmesh(obedit->data, em);
+                       return;
+               }
+               
+               for(efa_index=0, efa= em->faces.first; efa; efa_index++, efa= efa->next) {
+                       if(efa->tmp.l) {
+                               tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                               nverts= efa->v4? 4: 3;
+
+                               for(i=0; i<nverts; i++) {
+                                       if(select)
+                                               uvedit_uv_select(scene, efa, tf, i);
+                                       else
+                                               uvedit_uv_deselect(scene, efa, tf, i);
+                                       
+                                       vlist_iter= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l);
+                                       
+                                       while (vlist_iter) {
+                                               if(vlist_iter->separate)
+                                                       start_vlist = vlist_iter;
+                                               
+                                               if(efa_index == vlist_iter->f)
+                                                       break;
+
+                                               vlist_iter = vlist_iter->next;
+                                       }
+                               
+                                       vlist_iter = start_vlist;
+                                       while (vlist_iter) {
+                                               
+                                               if(vlist_iter != start_vlist && vlist_iter->separate)
+                                                       break;
+                                               
+                                               if(efa_index != vlist_iter->f) {
+                                                       efa_vlist = EM_get_face_for_index(vlist_iter->f);
+                                                       tf_vlist = CustomData_em_get(&em->fdata, efa_vlist->data, CD_MTFACE);
                                                        
-                                                       if(select)      uvedit_uv_select(scene, efa, tface, 2);
-                                                       else            uvedit_uv_deselect(scene, efa, tface, 2);
-                                               }
-                                               if((efa->v4) && (tface->unwrap & TF_PIN4) && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
-                                                       if(select)      uvedit_uv_select(scene, efa, tface, 3);
-                                                       else            uvedit_uv_deselect(scene, efa, tface, 3);
+                                                       if(select)
+                                                               uvedit_uv_select(scene, efa_vlist, tf_vlist, vlist_iter->tfindex);
+                                                       else
+                                                               uvedit_uv_deselect(scene, efa_vlist, tf_vlist, vlist_iter->tfindex);
                                                }
+                                               vlist_iter = vlist_iter->next;
                                        }
                                }
                        }
                }
-               if(ok) {
-                       /* make sure newly selected vert selection is updated*/
-                       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-                               if(scene->selectmode != SCE_SELECT_FACE) {
-                                       if(select)      EM_select_flush(em);
-                                       else            EM_deselect_flush(em);
-                               }
+               EM_free_index_arrays();
+               EM_free_uv_vert_map(vmap);
+               
+       }
+       else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       if(efa->tmp.l) {
+                               tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                               if(select)
+                                       uvedit_face_select(scene, efa, tf);
+                               else
+                                       uvedit_face_deselect(scene, efa, tf);
                        }
-                       // XXX allqueue(REDRAWVIEW3D, 0); /* mesh selection has changed */
-                       
-                       // XXX BIF_undo_push("Border select UV");
-                       // XXX scrarea_queue_winredraw(curarea);
                }
        }
+       BKE_mesh_end_editmesh(obedit->data, em);
 }
 
-int snap_uv_sel_to_curs(Scene *scene, Image *ima, Object *obedit, View2D *v2d)
+static int border_select_exec(bContext *C, wmOperator *op)
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       SpaceImage *sima= CTX_wm_space_image(C);
+       Scene *scene= CTX_data_scene(C);
+       ToolSettings *ts= CTX_data_tool_settings(C);
+       Object *obedit= CTX_data_edit_object(C);
+       Image *ima= CTX_data_edit_image(C);
+       ARegion *ar= CTX_wm_region(C);
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        EditFace *efa;
        MTFace *tface;
-       short change = 0;
+       rcti rect;
+       rctf rectf;
+       int change, pinned, select, faces;
 
-       for(efa= em->faces.first; efa; efa= efa->next) {
-               tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-               if(uvedit_face_visible(scene, ima, efa, tface)) {
-                       if(uvedit_uv_selected(scene, efa, tface, 0))            VECCOPY2D(tface->uv[0], v2d->cursor);
-                       if(uvedit_uv_selected(scene, efa, tface, 1))            VECCOPY2D(tface->uv[1], v2d->cursor);
-                       if(uvedit_uv_selected(scene, efa, tface, 2))            VECCOPY2D(tface->uv[2], v2d->cursor);
-                       if(efa->v4)
-                               if(uvedit_uv_selected(scene, efa, tface, 3))    VECCOPY2D(tface->uv[3], v2d->cursor);
-                       change = 1;
-               }
-       }
-       return change;
-}
+       /* get rectangle from operator */
+       rect.xmin= RNA_int_get(op->ptr, "xmin");
+       rect.ymin= RNA_int_get(op->ptr, "ymin");
+       rect.xmax= RNA_int_get(op->ptr, "xmax");
+       rect.ymax= RNA_int_get(op->ptr, "ymax");
+               
+       UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
+       UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
 
-int snap_uv_sel_to_adj_unsel(Scene *scene, Image *ima, Object *obedit)
-{
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
-       EditFace *efa;
-       EditVert *eve;
-       MTFace *tface;
-       short change = 0;
-       int count = 0;
-       float *coords;
-       short *usercount, users;
-       
-       /* set all verts to -1 : an unused index*/
-       for(eve= em->verts.first; eve; eve= eve->next)
-               eve->tmp.l=-1;
+       /* figure out what to select/deselect */
+       select= (RNA_int_get(op->ptr, "event_type") == LEFTMOUSE); // XXX hardcoded
+       pinned= RNA_boolean_get(op->ptr, "pinned");
        
-       /* index every vert that has a selected UV using it, but only once so as to
-        * get unique indicies and to count how much to malloc */
-       for(efa= em->faces.first; efa; efa= efa->next) {
-               tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-               if(uvedit_face_visible(scene, ima, efa, tface)) {
-                       if(uvedit_uv_selected(scene, efa, tface, 0) && efa->v1->tmp.l==-1)              efa->v1->tmp.l= count++;
-                       if(uvedit_uv_selected(scene, efa, tface, 1) && efa->v2->tmp.l==-1)              efa->v2->tmp.l= count++;
-                       if(uvedit_uv_selected(scene, efa, tface, 2) && efa->v3->tmp.l==-1)              efa->v3->tmp.l= count++;
-                       if(efa->v4)
-                               if(uvedit_uv_selected(scene, efa, tface, 3) && efa->v4->tmp.l==-1)      efa->v4->tmp.l= count++;
-                       change = 1;
-                       
-                       /* optional speedup */
-                       efa->tmp.p = tface;
+       if(ts->uv_flag & UV_SYNC_SELECTION)
+               faces= (ts->selectmode == SCE_SELECT_FACE);
+       else
+               faces= (ts->uv_selectmode == UV_SELECT_FACE);
+
+       /* do actual selection */
+       if(faces && !pinned) {
+               /* handle face selection mode */
+               float cent[2];
+
+               change= 0;
+
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       /* assume not touched */
+                       efa->tmp.l = 0;
+                       tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                       if(uvedit_face_visible(scene, ima, efa, tface)) {
+                               uv_center(tface->uv, cent, efa->v4 != NULL);
+                               if(BLI_in_rctf(&rectf, cent[0], cent[1])) {
+                                       efa->tmp.l = change = 1;
+                               }
+                       }
                }
-               else
-                       efa->tmp.p = NULL;
+
+               /* (de)selects all tagged faces and deals with sticky modes */
+               if(change)
+                       uv_faces_do_sticky(C, sima, scene, obedit, select);
        }
-       
-       coords = MEM_callocN(sizeof(float)*count*2, "snap to adjacent coords");
-       usercount = MEM_callocN(sizeof(short)*count, "snap to adjacent counts");
-       
-       /* add all UV coords from visible, unselected UV coords as well as counting them to average later */
-       for(efa= em->faces.first; efa; efa= efa->next) {
-//             tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-//             if(uvedit_face_visible(scene, ima, efa, tface)) {
-               if((tface=(MTFace *)efa->tmp.p)) {
+       else {
+               /* other selection modes */
+               change= 1;
+
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                       if(uvedit_face_visible(scene, ima, efa, tface)) {
+                               if(!pinned || (ts->uv_flag & UV_SYNC_SELECTION) ) {
+                                       /* UV_SYNC_SELECTION - can't do pinned selection */
+                                       if(BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
+                                               if(select)      uvedit_uv_select(scene, efa, tface, 0);
+                                               else            uvedit_uv_deselect(scene, efa, tface, 0);
+                                       }
+                                       if(BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
+                                               if(select)      uvedit_uv_select(scene, efa, tface, 1);
+                                               else            uvedit_uv_deselect(scene, efa, tface, 1);
+                                       }
+                                       if(BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
+                                               if(select)      uvedit_uv_select(scene, efa, tface, 2);
+                                               else            uvedit_uv_deselect(scene, efa, tface, 2);
+                                       }
+                                       if(efa->v4 && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
+                                               if(select)      uvedit_uv_select(scene, efa, tface, 3);
+                                               else            uvedit_uv_deselect(scene, efa, tface, 3);
+                                       }
+                               }
+                               else if(pinned) {
+                                       if((tface->unwrap & TF_PIN1) && 
+                                               BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
+                                               
+                                               if(select)      uvedit_uv_select(scene, efa, tface, 0);
+                                               else            uvedit_uv_deselect(scene, efa, tface, 0);
+                                       }
+                                       if((tface->unwrap & TF_PIN2) && 
+                                               BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
+                                               
+                                               if(select)      uvedit_uv_select(scene, efa, tface, 1);
+                                               else            uvedit_uv_deselect(scene, efa, tface, 1);
+                                       }
+                                       if((tface->unwrap & TF_PIN3) && 
+                                               BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
+                                               
+                                               if(select)      uvedit_uv_select(scene, efa, tface, 2);
+                                               else            uvedit_uv_deselect(scene, efa, tface, 2);
+                                       }
+                                       if((efa->v4) && (tface->unwrap & TF_PIN4) && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
+                                               if(select)      uvedit_uv_select(scene, efa, tface, 3);
+                                               else            uvedit_uv_deselect(scene, efa, tface, 3);
+                                       }
+                               }
+                       }
+               }
+       }
+
+       if(change) {
+               /* make sure newly selected vert selection is updated*/
+               if(ts->uv_flag & UV_SYNC_SELECTION) {
+                       if(ts->selectmode != SCE_SELECT_FACE) {
+                               if(select)      EM_select_flush(em);
+                               else            EM_deselect_flush(em);
+                       }
+               }
+
+               WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+               
+               BKE_mesh_end_editmesh(obedit->data, em);
+               return OPERATOR_FINISHED;
+       }
+       
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_CANCELLED;
+} 
+
+void UV_OT_select_border(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Border Select";
+       ot->idname= "UV_OT_select_border";
+       
+       /* api callbacks */
+       ot->invoke= WM_border_select_invoke;
+       ot->exec= border_select_exec;
+       ot->modal= WM_border_select_modal;
+       ot->poll= ED_operator_uvedit;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* properties */
+       RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only.");
+
+       RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "xmin", 0, INT_MIN, INT_MAX, "X Min", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "xmax", 0, INT_MIN, INT_MAX, "X Max", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "ymin", 0, INT_MIN, INT_MAX, "Y Min", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "ymax", 0, INT_MIN, INT_MAX, "Y Max", "", INT_MIN, INT_MAX);
+}
+
+/* ******************** circle select operator **************** */
+
+static void select_uv_inside_ellipse(SpaceImage *sima, Scene *scene, int select, EditFace *efa, MTFace *tface, int index, float *offset, float *ell, int select_index)
+{
+       /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
+       float x, y, r2, *uv;
+       
+       uv= tface->uv[index];
+
+       x= (uv[0] - offset[0])*ell[0];
+       y= (uv[1] - offset[1])*ell[1];
+
+       r2 = x*x + y*y;
+       if(r2 < 1.0) {
+               if(select)      uvedit_uv_select(scene, efa, tface, select_index);
+               else uvedit_uv_deselect(scene, efa, tface, select_index);
+       }
+}
+
+int circle_select_exec(bContext *C, wmOperator *op)
+{
+       SpaceImage *sima= CTX_wm_space_image(C);
+       Scene *scene= CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+       ARegion *ar= CTX_wm_region(C);
+       EditFace *efa;
+       MTFace *tface;
+       int x, y, radius, width, height, select;
+       float zoomx, zoomy, offset[2], ellipse[2];
+
+       /* get operator properties */
+       select= (RNA_int_get(op->ptr, "event_type") == LEFTMOUSE); // XXX hardcoded
+       x= RNA_int_get(op->ptr, "x");
+       y= RNA_int_get(op->ptr, "y");
+       radius= RNA_int_get(op->ptr, "radius");
+
+       /* compute ellipse size and location, not a circle since we deal
+        * with non square image. ellipse is normalized, r = 1.0. */
+       ED_space_image_size(sima, &width, &height);
+       ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
+
+       ellipse[0]= width*zoomx/radius;
+       ellipse[1]= height*zoomy/radius;
+
+       UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
+       
+       /* do selection */
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+               select_uv_inside_ellipse(sima, scene, select, efa, tface, 0, offset, ellipse, 0);
+               select_uv_inside_ellipse(sima, scene, select, efa, tface, 1, offset, ellipse, 1);
+               select_uv_inside_ellipse(sima, scene, select, efa, tface, 2, offset, ellipse, 2);
+               if(efa->v4)
+                       select_uv_inside_ellipse(sima, scene, select, efa, tface, 3, offset, ellipse, 3);
+       }
+
+       if(select) EM_select_flush(em);
+       else EM_deselect_flush(em);
+
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;
+}
+
+void UV_OT_circle_select(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Circle Select";
+       ot->idname= "UV_OT_circle_select";
+       
+       /* api callbacks */
+       ot->invoke= WM_gesture_circle_invoke;
+       ot->modal= WM_gesture_circle_modal;
+       ot->exec= circle_select_exec;
+       ot->poll= ED_operator_uvedit;
+       
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* properties */
+       RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
+       RNA_def_int(ot->srna, "event_type", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX);
+}
+
+/* ******************** snap cursor operator **************** */
+
+static void snap_uv_to_pixel(float *uvco, float w, float h)
+{
+       uvco[0] = ((float)((int)((uvco[0]*w) + 0.5f)))/w;
+       uvco[1] = ((float)((int)((uvco[1]*h) + 0.5f)))/h;
+}
+
+static void snap_cursor_to_pixels(SpaceImage *sima, View2D *v2d)
+{
+       int width= 0, height= 0;
+
+       ED_space_image_size(sima, &width, &height);
+       snap_uv_to_pixel(v2d->cursor, width, height);
+}
+
+static int snap_cursor_to_selection(Scene *scene, Image *ima, Object *obedit, View2D *v2d)
+{
+       return uvedit_center(scene, ima, obedit, v2d->cursor, 0);
+}
+
+static int snap_cursor_exec(bContext *C, wmOperator *op)
+{
+       SpaceImage *sima= CTX_wm_space_image(C);
+       Scene *scene= CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       Image *ima= CTX_data_edit_image(C);
+       ARegion *ar= CTX_wm_region(C);
+       int change= 0;
+
+       switch(RNA_boolean_get(op->ptr, "target")) {
+               case 0:
+                       snap_cursor_to_pixels(sima, &ar->v2d);
+                       change= 1;
+                       break;
+               case 1:
+                       change= snap_cursor_to_selection(scene, ima, obedit, &ar->v2d);
+                       break;
+       }
+
+       if(!change)
+               return OPERATOR_CANCELLED;
+       
+       ED_region_tag_redraw(ar);
+
+       return OPERATOR_FINISHED;
+}
+
+void UV_OT_snap_cursor(wmOperatorType *ot)
+{
+       static EnumPropertyItem target_items[] = {
+               {0, "PIXELS", 0, "Pixels", ""},
+               {1, "SELECTION", 0, "Selection", ""},
+               {0, NULL, 0, NULL, NULL}};
+
+       /* identifiers */
+       ot->name= "Snap Cursor";
+       ot->idname= "UV_OT_snap_cursor";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* api callbacks */
+       ot->exec= snap_cursor_exec;
+       ot->poll= ED_operator_uvedit;
+
+       /* properties */
+       RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UV's to.");
+}
+
+/* ******************** snap selection operator **************** */
+
+static int snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, View2D *v2d)
+{
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+       EditFace *efa;
+       MTFace *tface;
+       short change= 0;
+
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+               if(uvedit_face_visible(scene, ima, efa, tface)) {
+                       if(uvedit_uv_selected(scene, efa, tface, 0))            VECCOPY2D(tface->uv[0], v2d->cursor);
+                       if(uvedit_uv_selected(scene, efa, tface, 1))            VECCOPY2D(tface->uv[1], v2d->cursor);
+                       if(uvedit_uv_selected(scene, efa, tface, 2))            VECCOPY2D(tface->uv[2], v2d->cursor);
+                       if(efa->v4)
+                               if(uvedit_uv_selected(scene, efa, tface, 3))    VECCOPY2D(tface->uv[3], v2d->cursor);
+
+                       change= 1;
+               }
+       }
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return change;
+}
+
+static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit)
+{
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+       EditFace *efa;
+       EditVert *eve;
+       MTFace *tface;
+       short change = 0;
+       int count = 0;
+       float *coords;
+       short *usercount, users;
+       
+       /* set all verts to -1 : an unused index*/
+       for(eve= em->verts.first; eve; eve= eve->next)
+               eve->tmp.l=-1;
+       
+       /* index every vert that has a selected UV using it, but only once so as to
+        * get unique indicies and to count how much to malloc */
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+               if(uvedit_face_visible(scene, ima, efa, tface)) {
+                       if(uvedit_uv_selected(scene, efa, tface, 0) && efa->v1->tmp.l==-1)              efa->v1->tmp.l= count++;
+                       if(uvedit_uv_selected(scene, efa, tface, 1) && efa->v2->tmp.l==-1)              efa->v2->tmp.l= count++;
+                       if(uvedit_uv_selected(scene, efa, tface, 2) && efa->v3->tmp.l==-1)              efa->v3->tmp.l= count++;
+                       if(efa->v4)
+                               if(uvedit_uv_selected(scene, efa, tface, 3) && efa->v4->tmp.l==-1)      efa->v4->tmp.l= count++;
+
+                       change = 1;
                        
+                       /* optional speedup */
+                       efa->tmp.p = tface;
+               }
+               else
+                       efa->tmp.p = NULL;
+       }
+       
+       coords = MEM_callocN(sizeof(float)*count*2, "snap to adjacent coords");
+       usercount = MEM_callocN(sizeof(short)*count, "snap to adjacent counts");
+       
+       /* add all UV coords from visible, unselected UV coords as well as counting them to average later */
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               if((tface=(MTFace *)efa->tmp.p)) {
                        /* is this an unselected UV we can snap to? */
                        if(efa->v1->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 0))) {
                                coords[efa->v1->tmp.l*2] +=             tface->uv[0][0];
@@ -2113,13 +2423,12 @@ int snap_uv_sel_to_adj_unsel(Scene *scene, Image *ima, Object *obedit)
        if(!change) {
                MEM_freeN(coords);
                MEM_freeN(usercount);
+               BKE_mesh_end_editmesh(obedit->data, em);
                return change;
        }
        
        /* copy the averaged unselected UVs back to the selected UVs */
        for(efa= em->faces.first; efa; efa= efa->next) {
-//             tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-//             if(uvedit_face_visible(scene, ima, efa, tface)) {
                if((tface=(MTFace *)efa->tmp.p)) {
                        
                        if(     uvedit_uv_selected(scene, efa, tface, 0) &&
@@ -2160,423 +2469,665 @@ int snap_uv_sel_to_adj_unsel(Scene *scene, Image *ima, Object *obedit)
        
        MEM_freeN(coords);
        MEM_freeN(usercount);
-       return change;
-}
 
-void snap_coord_to_pixel(float *uvco, float w, float h)
-{
-       uvco[0] = ((float) ((int)((uvco[0]*w) + 0.5))) / w;  
-       uvco[1] = ((float) ((int)((uvco[1]*h) + 0.5))) / h;  
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return change;
 }
 
-int snap_uv_sel_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit) /* warning, sanity checks must alredy be done */
+static int snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
-       Image *ima= sima->image;
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+       Image *ima;
        EditFace *efa;
        MTFace *tface;
        int width= 0, height= 0;
        float w, h;
        short change = 0;
 
-       // XXX get_space_image_size(sima, &width, &height);
+       if(!sima)
+               return 0;
+       
+       ima= sima->image;
+       
+       ED_space_image_size(sima, &width, &height);
        w = (float)width;
        h = (float)height;
        
        for(efa= em->faces.first; efa; efa= efa->next) {
                tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
                if(uvedit_face_visible(scene, ima, efa, tface)) {
-                       if(uvedit_uv_selected(scene, efa, tface, 0)) snap_coord_to_pixel(tface->uv[0], w, h);
-                       if(uvedit_uv_selected(scene, efa, tface, 1)) snap_coord_to_pixel(tface->uv[1], w, h);
-                       if(uvedit_uv_selected(scene, efa, tface, 2)) snap_coord_to_pixel(tface->uv[2], w, h);
+                       if(uvedit_uv_selected(scene, efa, tface, 0)) snap_uv_to_pixel(tface->uv[0], w, h);
+                       if(uvedit_uv_selected(scene, efa, tface, 1)) snap_uv_to_pixel(tface->uv[1], w, h);
+                       if(uvedit_uv_selected(scene, efa, tface, 2)) snap_uv_to_pixel(tface->uv[2], w, h);
                        if(efa->v4)
-                               if(uvedit_uv_selected(scene, efa, tface, 3)) snap_coord_to_pixel(tface->uv[3], w, h);
+                               if(uvedit_uv_selected(scene, efa, tface, 3)) snap_uv_to_pixel(tface->uv[3], w, h);
+
                        change = 1;
                }
        }
-       return change;
-}
-
-void snap_uv_curs_to_pixels(SpaceImage *sima, View2D *v2d)
-{
-       int width= 0, height= 0;
-
-       // XXX get_space_image_size(sima, &width, &height);
-       snap_coord_to_pixel(v2d->cursor, width, height);
-}
 
-int snap_uv_curs_to_sel(Scene *scene, Image *ima, Object *obedit, View2D *v2d)
-{
-       if(!ED_uvedit_test(obedit)) return 0;
-       return uvedit_center(scene, ima, obedit, v2d->cursor, 0);
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return change;
 }
 
-void snap_menu_sima(SpaceImage *sima, Scene *scene, Object *obedit, View2D *v2d)
+static int snap_selection_exec(bContext *C, wmOperator *op)
 {
-       short event;
+       SpaceImage *sima= CTX_wm_space_image(C);
+       Scene *scene= CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       Image *ima= CTX_data_edit_image(C);
+       ARegion *ar= CTX_wm_region(C);
+       int change= 0;
 
-       if(!ED_uvedit_test(obedit) || !v2d) return; /* !G.v2d should never happen */
-       
-       event = 0; // XXX pupmenu("Snap %t|Selection -> Pixels%x1|Selection -> Cursor%x2|Selection -> Adjacent Unselected%x3|Cursor -> Selection%x4|Cursor -> Pixel%x5");
-       switch (event) {
+       switch(RNA_boolean_get(op->ptr, "target")) {
+               case 0:
+                       change= snap_uvs_to_pixels(sima, scene, obedit);
+                       break;
                case 1:
-                   if(snap_uv_sel_to_pixels(sima, scene, obedit)) {
-                       // XXX BIF_undo_push("Snap UV Selection to Pixels");
-                               DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-                   }
-                   break;
+                       change= snap_uvs_to_cursor(scene, ima, obedit, &ar->v2d);
+                       break;
                case 2:
-                   if(snap_uv_sel_to_curs(scene, sima->image, obedit, v2d)) {
-                       // XXX BIF_undo_push("Snap UV Selection to Cursor");
-                               DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-                   }
-                   break;
-               case 3:
-                   if(snap_uv_sel_to_adj_unsel(scene, sima->image, obedit)) {
-                       // XXX BIF_undo_push("Snap UV Selection to Cursor");
-                               DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-                   }
-                   break;
-               case 4:
-                   if(snap_uv_curs_to_sel(scene, sima->image, obedit, v2d))
-                       // XXX allqueue(REDRAWIMAGE, 0);
-                   break;
-               case 5:
-                   snap_uv_curs_to_pixels(sima, v2d);
-                       // XXX scrarea_queue_winredraw(curarea);
-                   break;
-       }
-}
-
-
-/** This is an ugly function to set the Tface selection flags depending
-  * on whether its UV coordinates are inside the normalized 
-  * area with radius rad and offset offset. These coordinates must be
-  * normalized to 1.0 
-  * Just for readability...
-  */
-
-static void sel_uvco_inside_radius(SpaceImage *sima, Scene *scene, short sel, EditFace *efa, MTFace *tface, int index, float *offset, float *ell, short select_index)
-{
-       // normalized ellipse: ell[0] = scaleX,
-       //                        [1] = scaleY
-
-       float *uv = tface->uv[index];
-       float x, y, r2;
-
-       x = (uv[0] - offset[0]) * ell[0];
-       y = (uv[1] - offset[1]) * ell[1];
-
-       r2 = x * x + y * y;
-       if(r2 < 1.0) {
-               if(sel == 0 /* XXX LEFTMOUSE */)        uvedit_uv_select(scene, efa, tface, select_index);
-               else                                    uvedit_uv_deselect(scene, efa, tface, select_index);
+                       change= snap_uvs_to_adjacent_unselected(scene, ima, obedit);
+                       break;
        }
+
+       if(!change)
+               return OPERATOR_CANCELLED;
+       
+       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+       return OPERATOR_FINISHED;
 }
 
-// see below:
-/** gets image dimensions of the 2D view 'v' */
-static void getSpaceImageDimension(SpaceImage *sima, ARegion *ar, float *xy)
+void UV_OT_snap_selection(wmOperatorType *ot)
 {
-       float zoomx= 0, zoomy= 0;
-       int width= 0, height= 0;
+       static EnumPropertyItem target_items[] = {
+               {0, "PIXELS", 0, "Pixels", ""},
+               {1, "CURSOR", 0, "Cursor", ""},
+               {2, "ADJACENT_UNSELECTED", 0, "Adjacent Unselected", ""},
+               {0, NULL, 0, NULL, NULL}};
 
-       // XXX get_space_image_size(sima, &width, &height);
-       // XXX get_space_image_zoom(sima, ar, &zoomx, &zoomy);
+       /* identifiers */
+       ot->name= "Snap Selection";
+       ot->idname= "UV_OT_snap_selection";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* api callbacks */
+       ot->exec= snap_selection_exec;
+       ot->poll= ED_operator_uvedit;
 
-       xy[0]= width*zoomx;
-       xy[1]= height*zoomy;
+       /* properties */
+       RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UV's to.");
 }
 
-/** Callback function called by circle_selectCB to enable 
-  * brush select in UV editor.
-  */
+/* ******************** pin operator **************** */
 
-void uvedit_selectionCB(SpaceImage *sima, Scene *scene, ARegion *ar, short selecting, Object *obedit, short *mval, float rad) 
+static int pin_exec(bContext *C, wmOperator *op)
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       Scene *scene= CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       Image *ima= CTX_data_edit_image(C);
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        EditFace *efa;
-       float offset[2];
        MTFace *tface;
-       float ellipse[2]; // we need to deal with ellipses, as
-                         // non square textures require for circle
-                                         // selection. this ellipse is normalized; r = 1.0
-
-       getSpaceImageDimension(sima, ar, ellipse);
-       ellipse[0] /= rad;
-       ellipse[1] /= rad;
-
-       // XXX areamouseco_to_ipoco(G.v2d, mval, &offset[0], &offset[1]);
+       int clear= RNA_boolean_get(op->ptr, "clear");
        
-       if(selecting) {
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                       sel_uvco_inside_radius(sima, scene, selecting, efa, tface, 0, offset, ellipse, 0);
-                       sel_uvco_inside_radius(sima, scene, selecting, efa, tface, 1, offset, ellipse, 1);
-                       sel_uvco_inside_radius(sima, scene, selecting, efa, tface, 2, offset, ellipse, 2);
-                       if(efa->v4)
-                               sel_uvco_inside_radius(sima, scene, selecting, efa, tface, 3, offset, ellipse, 3);
-               }
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 
-               /* XXX */
-#if 0
-               if(G.f & G_DRAWFACES) { /* full redraw only if necessary */
-                       draw_sel_circle(0, 0, 0, 0, 0); /* signal */
-                       force_draw(0);
-               }
-               else { /* force_draw() is no good here... */
-                       glDrawBuffer(GL_FRONT);
-                       draw_uvs_sima();
-                       bglFlush();
-                       glDrawBuffer(GL_BACK);
+               if(uvedit_face_visible(scene, ima, efa, tface)) {
+                       if(!clear) {
+                               if(uvedit_uv_selected(scene, efa, tface, 0)) tface->unwrap |= TF_PIN1;
+                               if(uvedit_uv_selected(scene, efa, tface, 1)) tface->unwrap |= TF_PIN2;
+                               if(uvedit_uv_selected(scene, efa, tface, 2)) tface->unwrap |= TF_PIN3;
+                               if(efa->v4)
+                                       if(uvedit_uv_selected(scene, efa, tface, 3)) tface->unwrap |= TF_PIN4;
+                       }
+                       else {
+                               if(uvedit_uv_selected(scene, efa, tface, 0)) tface->unwrap &= ~TF_PIN1;
+                               if(uvedit_uv_selected(scene, efa, tface, 1)) tface->unwrap &= ~TF_PIN2;
+                               if(uvedit_uv_selected(scene, efa, tface, 2)) tface->unwrap &= ~TF_PIN3;
+                               if(efa->v4)
+                                       if(uvedit_uv_selected(scene, efa, tface, 3)) tface->unwrap &= ~TF_PIN4;
+                       }
                }
-#endif 
-               
-               if(selecting == 0 /* XXX LEFTMOUSE */)  EM_select_flush(em);
-               else                                            EM_deselect_flush(em);
-               
-               if(sima->lock && (scene->toolsettings->uv_flag & UV_SYNC_SELECTION))
-                       ; // XXX force_draw_plus(SPACE_VIEW3D, 0);
        }
+       
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;
 }
 
-/* this function sets the selection on tagged faces
- * This is needed because setting the selection on a face is done in
- * a number of places but it also needs to respect the sticky modes
- * for the UV verts - dealing with the sticky modes is best done in a seperate function
- * 
- * de-selects faces that have been tagged on efa->tmp.l 
- */
-void uvface_setsel__internal(bContext *C, SpaceImage *sima, Scene *scene, Object *obedit, short select)
+void UV_OT_pin(wmOperatorType *ot)
 {
+       /* identifiers */
+       ot->name= "Pin";
+       ot->idname= "UV_OT_pin";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
-       /* All functions calling this should call
-        * draw_uvs_face_check() 
-        */
-       
-               
-       /* selecting UV Faces with some modes requires us to change 
-        * the selection in other faces (depending on the stickt mode)
-        * 
-        * This only needs to be done when the Mesh is not used for selection
-        * (So for sticky modes - vertex or location based)
-        * */
-       
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       /* api callbacks */
+       ot->exec= pin_exec;
+       ot->poll= ED_operator_uvedit;
+
+       /* properties */
+       RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it.");
+}
+
+/******************* select pinned operator ***************/
+
+static int select_pinned_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       Image *ima= CTX_data_edit_image(C);
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        EditFace *efa;
-       MTFace *tf;
-       int nverts, i;
+       MTFace *tface;
        
-       if((scene->toolsettings->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_VERTEX) {
-               /* tag all verts as untouched,
-                * then touch the ones that have a face center in the loop
-                * and select all MTFace UV's that use a touched vert */
-               
-               EditVert *eve;
-               
-               for(eve= em->verts.first; eve; eve= eve->next)
-                       eve->tmp.l = 0;
-               
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       if(efa->tmp.l) {
-                               if(efa->v4)
-                                       efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= efa->v4->tmp.l=1;
-                               else
-                                       efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= 1;
-                       }
-               }
-               /* now select tagged verts */
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);               
-                       nverts= efa->v4? 4: 3;
-                       for(i=0; i<nverts; i++) {
-                               if((*(&efa->v1 + i))->tmp.l) {
-                                       if(select)
-                                               uvedit_uv_select(scene, efa, tf, i);
-                                       else
-                                               uvedit_uv_deselect(scene, efa, tf, i);
-                               }
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+               if(uvedit_face_visible(scene, ima, efa, tface)) {
+                       if(tface->unwrap & TF_PIN1) uvedit_uv_select(scene, efa, tface, 0);
+                       if(tface->unwrap & TF_PIN2) uvedit_uv_select(scene, efa, tface, 1);
+                       if(tface->unwrap & TF_PIN3) uvedit_uv_select(scene, efa, tface, 2);
+                       if(efa->v4) {
+                               if(tface->unwrap & TF_PIN4) uvedit_uv_select(scene, efa, tface, 3);
                        }
                }
-       } else if((scene->toolsettings->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_LOC) {
-               EditFace *efa_vlist;
-               MTFace *tf_vlist;
-               UvMapVert *start_vlist=NULL, *vlist_iter;
-               struct UvVertMap *vmap;
-               float limit[2];
-               int efa_index;
-               //EditVert *eve; /* removed vert counting for now */ 
-               //int a;
-               
-               uvedit_pixel_to_float(C, limit, 0.05);
-               
-               EM_init_index_arrays(em, 0, 0, 1);
-               vmap= EM_make_uv_vert_map(em, 0, 0, limit);
-               
-               /* verts are numbered above in make_uv_vert_map_EM, make sure this stays true! */
-               /*for(a=0, eve= em->verts.first; eve; a++, eve= eve->next)
-                       eve->tmp.l = a; */
-               
-               if(vmap == NULL)
-                       return;
-               
-               for(efa_index=0, efa= em->faces.first; efa; efa_index++, efa= efa->next) {
-                       if(efa->tmp.l) {
-                               tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                               nverts= efa->v4? 4: 3;
+       }
+       
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
 
-                               for(i=0; i<nverts; i++) {
-                                       if(select)
-                                               uvedit_uv_select(scene, efa, tf, i);
-                                       else
-                                               uvedit_uv_deselect(scene, efa, tf, i);
-                                       
-                                       vlist_iter= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l);
-                                       
-                                       while (vlist_iter) {
-                                               if(vlist_iter->separate)
-                                                       start_vlist = vlist_iter;
-                                               
-                                               if(efa_index == vlist_iter->f)
-                                                       break;
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;
+}
 
-                                               vlist_iter = vlist_iter->next;
-                                       }
-                               
-                                       vlist_iter = start_vlist;
-                                       while (vlist_iter) {
-                                               
-                                               if(vlist_iter != start_vlist && vlist_iter->separate)
-                                                       break;
+void UV_OT_select_pinned(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Selected Pinned";
+       ot->idname= "UV_OT_select_pinned";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* api callbacks */
+       ot->exec= select_pinned_exec;
+       ot->poll= ED_operator_uvedit;
+}
+
+/********************** hide operator *********************/
+
+static int hide_exec(bContext *C, wmOperator *op)
+{
+       SpaceImage *sima= CTX_wm_space_image(C);
+       ToolSettings *ts= CTX_data_tool_settings(C);
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+       EditFace *efa;
+       MTFace *tf;
+       int swap= RNA_boolean_get(op->ptr, "unselected");
+       int facemode= sima ? sima->flag & SI_SELACTFACE : 0;
+
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               EM_hide_mesh(em, swap);
+               WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+               BKE_mesh_end_editmesh(obedit->data, em);
+               return OPERATOR_FINISHED;
+       }
+       
+       if(swap) {
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       if(efa->f & SELECT) {
+                               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                               if(facemode) {
+                                       /* Pretend face mode */
+                                       if((    (efa->v4==NULL && 
+                                                       (       tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) ==                        (TF_SEL1|TF_SEL2|TF_SEL3) )                      ||
+                                                       (       tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) ==        (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)       ) == 0) {
                                                
-                                               if(efa_index != vlist_iter->f) {
-                                                       efa_vlist = EM_get_face_for_index(vlist_iter->f);
-                                                       tf_vlist = CustomData_em_get(&em->fdata, efa_vlist->data, CD_MTFACE);
-                                                       
-                                                       if(select)
-                                                               uvedit_uv_select(scene, efa_vlist, tf_vlist, vlist_iter->tfindex);
-                                                       else
-                                                               uvedit_uv_deselect(scene, efa_vlist, tf_vlist, vlist_iter->tfindex);
+                                               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;
                                                }
-                                               vlist_iter = vlist_iter->next;
+                                               else
+                                                       EM_select_face(efa, 0);
+                                       }
+                                       tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+                               }
+                               else if(em->selectmode == SCE_SELECT_FACE) {
+                                       if((tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3))==0) {
+                                               if(!efa->v4)
+                                                       EM_select_face(efa, 0);
+                                               else if(!(tf->flag & TF_SEL4))
+                                                       EM_select_face(efa, 0);
+                                               tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
                                        }
                                }
+                               else {
+                                       /* EM_deselect_flush will deselect the face */
+                                       if((tf->flag & TF_SEL1)==0)                             efa->v1->f &= ~SELECT;
+                                       if((tf->flag & TF_SEL2)==0)                             efa->v2->f &= ~SELECT;
+                                       if((tf->flag & TF_SEL3)==0)                             efa->v3->f &= ~SELECT;
+                                       if((efa->v4) && (tf->flag & TF_SEL4)==0)        efa->v4->f &= ~SELECT;                  
+
+                                       tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+                               }
                        }
                }
-               EM_free_index_arrays();
-               EM_free_uv_vert_map(vmap);
-               
        }
-       else { /* SI_STICKY_DISABLE or scene->toolsettings->uv_flag & UV_SYNC_SELECTION */
+       else {
                for(efa= em->faces.first; efa; efa= efa->next) {
-                       if(efa->tmp.l) {
-                               tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                               if(select)
-                                       uvedit_face_select(scene, efa, tf);
-                               else
-                                       uvedit_face_deselect(scene, efa, tf);
+                       if(efa->f & SELECT) {
+                               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+                               if(facemode) {
+                                       if(     (efa->v4==NULL && 
+                                                       (       tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) ==                        (TF_SEL1|TF_SEL2|TF_SEL3) )                      ||
+                                                       (       tf->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);
+                                       }
+
+                                       tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+                               }
+                               else if(em->selectmode == SCE_SELECT_FACE) {
+                                       if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
+                                               EM_select_face(efa, 0);
+                                       else if(efa->v4 && tf->flag & TF_SEL4)
+                                               EM_select_face(efa, 0);
+
+                                       tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+                               }
+                               else {
+                                       /* EM_deselect_flush will deselect the face */
+                                       if(tf->flag & TF_SEL1)                          efa->v1->f &= ~SELECT;
+                                       if(tf->flag & TF_SEL2)                          efa->v2->f &= ~SELECT;
+                                       if(tf->flag & TF_SEL3)                          efa->v3->f &= ~SELECT;
+                                       if((efa->v4) && tf->flag & TF_SEL4)     efa->v4->f &= ~SELECT;
+
+                                       tf->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(em);
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;
 }
 
-void pin_tface_uv(Scene *scene, Image *ima, Object *obedit, int mode)
+void UV_OT_hide(wmOperatorType *ot)
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       /* identifiers */
+       ot->name= "Hide Selected";
+       ot->idname= "UV_OT_hide";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* api callbacks */
+       ot->exec= hide_exec;
+       ot->poll= ED_operator_uvedit;
+
+       /* props */
+       RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
+}
+
+/****************** reveal operator ******************/
+
+static int reveal_exec(bContext *C, wmOperator *op)
+{
+       SpaceImage *sima= CTX_wm_space_image(C);
+       ToolSettings *ts= CTX_data_tool_settings(C);
+       Object *obedit= CTX_data_edit_object(C);
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        EditFace *efa;
-       MTFace *tface;
+       MTFace *tf;
+       int facemode= sima ? sima->flag & SI_SELACTFACE : 0;
+       int stickymode= sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
        
-       if(!ED_uvedit_test(obedit)) return;
+       /* call the mesh function if we are in mesh sync sel */
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               EM_reveal_mesh(em);
+               WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+               BKE_mesh_end_editmesh(obedit->data, em);
+               return OPERATOR_FINISHED;
+       }
        
-       for(efa= em->faces.first; efa; efa= efa->next) {
-               tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-               if(uvedit_face_visible(scene, ima, efa, tface)) {
-                       if(mode ==1) {
-                               if(uvedit_uv_selected(scene, efa, tface, 0)) tface->unwrap |= TF_PIN1;
-                               if(uvedit_uv_selected(scene, efa, tface, 1)) tface->unwrap |= TF_PIN2;
-                               if(uvedit_uv_selected(scene, efa, tface, 2)) tface->unwrap |= TF_PIN3;
-                               if(efa->v4)
-                                       if(uvedit_uv_selected(scene, efa, tface, 3)) tface->unwrap |= TF_PIN4;
+       if(facemode) {
+               if(em->selectmode == SCE_SELECT_FACE) {
+                       for(efa= em->faces.first; efa; efa= efa->next) {
+                               if(!(efa->h) && !(efa->f & SELECT)) {
+                                       tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                                       EM_select_face(efa, 1);
+                                       tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
+                               }
                        }
-                       else if(mode ==0) {
-                               if(uvedit_uv_selected(scene, efa, tface, 0)) tface->unwrap &= ~TF_PIN1;
-                               if(uvedit_uv_selected(scene, efa, tface, 1)) tface->unwrap &= ~TF_PIN2;
-                               if(uvedit_uv_selected(scene, efa, tface, 2)) tface->unwrap &= ~TF_PIN3;
-                               if(efa->v4)
-                                       if(uvedit_uv_selected(scene, efa, tface, 3)) tface->unwrap &= ~TF_PIN4;
+               }
+               else {
+                       /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
+                       if(!stickymode) {
+                               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)) {
+                                                       tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+                                                       tf->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)) {
+                                               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+                                               if((efa->v1->f & SELECT)==0)                            {tf->flag |= TF_SEL1;}
+                                               if((efa->v2->f & SELECT)==0)                            {tf->flag |= TF_SEL2;}
+                                               if((efa->v3->f & SELECT)==0)                            {tf->flag |= TF_SEL3;}
+                                               if((efa->v4 && (efa->v4->f & SELECT)==0))       {tf->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)) {
+                               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                               efa->f |= SELECT;
+                               tf->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)) {
+                               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+                               if((efa->v1->f & SELECT)==0)                            {tf->flag |= TF_SEL1;}
+                               if((efa->v2->f & SELECT)==0)                            {tf->flag |= TF_SEL2;}
+                               if((efa->v3->f & SELECT)==0)                            {tf->flag |= TF_SEL3;}
+                               if((efa->v4 && (efa->v4->f & SELECT)==0))       {tf->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);
+       }
+
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;
+}
+
+void UV_OT_reveal(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Reveal Hidden";
+       ot->idname= "UV_OT_reveal";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
-       // XXX BIF_undo_push("Pin UV");
-       // XXX scrarea_queue_winredraw(curarea);
+       /* api callbacks */
+       ot->exec= reveal_exec;
+       ot->poll= ED_operator_uvedit;
 }
 
-void select_pinned_tface_uv(Scene *scene, Image *ima, Object *obedit)
+/******************** set 3d cursor operator ********************/
+
+static int set_2d_cursor_exec(bContext *C, wmOperator *op)
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
-       EditFace *efa;
-       MTFace *tface;
+       ARegion *ar= CTX_wm_region(C);
+       float location[2];
+
+       RNA_float_get_array(op->ptr, "location", location);
+       ar->v2d.cursor[0]= location[0];
+       ar->v2d.cursor[1]= location[1];
        
-       if(!ED_uvedit_test(obedit)) return;
+       ED_area_tag_redraw(CTX_wm_area(C));
        
-       for(efa= em->faces.first; efa; efa= efa->next) {
-               tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-               if(uvedit_face_visible(scene, ima, efa, tface)) {
-                       if(tface->unwrap & TF_PIN1) uvedit_uv_select(scene, efa, tface, 0);
-                       if(tface->unwrap & TF_PIN2) uvedit_uv_select(scene, efa, tface, 1);
-                       if(tface->unwrap & TF_PIN3) uvedit_uv_select(scene, efa, tface, 2);
-                       if(efa->v4) {
-                               if(tface->unwrap & TF_PIN4) uvedit_uv_select(scene, efa, tface, 3);
-                       }
-                       
-               }
-       }
+       return OPERATOR_FINISHED;
+}
+
+static int set_2d_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       ARegion *ar= CTX_wm_region(C);
+       int x, y;
+       float location[2];
+
+       x= event->x - ar->winrct.xmin;
+       y= event->y - ar->winrct.ymin;
+       UI_view2d_region_to_view(&ar->v2d, x, y, &location[0], &location[1]);
+       RNA_float_set_array(op->ptr, "location", location);
+
+       return set_2d_cursor_exec(C, op);
+}
+
+void UV_OT_cursor_set(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Set 3D Cursor";
+       ot->idname= "UV_OT_cursor_set";
        
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               // XXX allqueue(REDRAWVIEW3D, 0); /* mesh selection has changed */
+       /* api callbacks */
+       ot->exec= set_2d_cursor_exec;
+       ot->invoke= set_2d_cursor_invoke;
+       ot->poll= ED_operator_uvedit;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* properties */
+       RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX, "Location", "Cursor location in 0.0-1.0 coordinates.", -10.0f, 10.0f);
+}
+
+/********************** set tile operator **********************/
+
+static int set_tile_exec(bContext *C, wmOperator *op)
+{
+       Image *ima= CTX_data_edit_image(C);
+       int tile[2];
+
+       if(!ima || !(ima->tpageflag & IMA_TILES))
+               return OPERATOR_CANCELLED;
+
+       RNA_int_get_array(op->ptr, "tile", tile);
+       ED_uvedit_set_tile(C, CTX_data_scene(C), CTX_data_edit_object(C), ima, tile[0] + ima->xrep*tile[1]);
+
+       ED_area_tag_redraw(CTX_wm_area(C));
+
+       return OPERATOR_FINISHED;
+}
+
+static int set_tile_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       SpaceImage *sima= CTX_wm_space_image(C);
+       Image *ima= CTX_data_edit_image(C);
+       ARegion *ar= CTX_wm_region(C);
+       float fx, fy;
+       int x, y, tile[2];
+
+       if(!ima || !(ima->tpageflag & IMA_TILES))
+               return OPERATOR_CANCELLED;
+
+       x= event->x - ar->winrct.xmin;
+       y= event->y - ar->winrct.ymin;
+       UI_view2d_region_to_view(&ar->v2d, x, y, &fx, &fy);
+
+       if(fx>=0.0 && fy>=0.0 && fx<1.0 && fy<1.0) {
+               fx= fx*ima->xrep;
+               fy= fy*ima->yrep;
+               
+               tile[0]= fx;
+               tile[1]= fy;
+               
+               sima->curtile= tile[1]*ima->xrep + tile[0];
+               RNA_int_set_array(op->ptr, "tile", tile);
        }
+
+       return set_tile_exec(C, op);
+}
+
+void UV_OT_tile_set(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Set Tile";
+       ot->idname= "UV_OT_tile_set";
        
-       // XXX BIF_undo_push("Select Pinned UVs");
-       // XXX scrarea_queue_winredraw(curarea);
+       /* api callbacks */
+       ot->exec= set_tile_exec;
+       ot->invoke= set_tile_invoke;
+       ot->poll= ED_operator_uvedit;
+
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+
+       /* properties */
+       RNA_def_int_vector(ot->srna, "tile", 2, NULL, 0, INT_MAX, "Tile", "Tile coordinate.", 0, 10);
 }
 
 /* ************************** registration **********************************/
 
 void ED_operatortypes_uvedit(void)
 {
-       WM_operatortype_append(UV_OT_de_select_all);
-       WM_operatortype_append(UV_OT_select_invert);
+       WM_operatortype_append(UV_OT_select_all_toggle);
+       WM_operatortype_append(UV_OT_select_inverse);
        WM_operatortype_append(UV_OT_select);
-       WM_operatortype_append(UV_OT_loop_select);
+       WM_operatortype_append(UV_OT_select_loop);
        WM_operatortype_append(UV_OT_select_linked);
        WM_operatortype_append(UV_OT_unlink_selection);
+       WM_operatortype_append(UV_OT_select_pinned);
+       WM_operatortype_append(UV_OT_select_border);
+       WM_operatortype_append(UV_OT_circle_select);
+
+       WM_operatortype_append(UV_OT_snap_cursor);
+       WM_operatortype_append(UV_OT_snap_selection);
 
        WM_operatortype_append(UV_OT_align);
-       WM_operatortype_append(UV_OT_mirror);
        WM_operatortype_append(UV_OT_stitch);
        WM_operatortype_append(UV_OT_weld);
+       WM_operatortype_append(UV_OT_pin);
+
+       WM_operatortype_append(UV_OT_average_islands_scale);
+       WM_operatortype_append(UV_OT_cube_project);
+       WM_operatortype_append(UV_OT_cylinder_project);
+       WM_operatortype_append(UV_OT_from_view);
+       WM_operatortype_append(UV_OT_mapping_menu);
+       WM_operatortype_append(UV_OT_minimize_stretch);
+       WM_operatortype_append(UV_OT_pack_islands);
+       WM_operatortype_append(UV_OT_reset);
+       WM_operatortype_append(UV_OT_sphere_project);
+       WM_operatortype_append(UV_OT_unwrap);
+
+       WM_operatortype_append(UV_OT_reveal);
+       WM_operatortype_append(UV_OT_hide);
+
+       WM_operatortype_append(UV_OT_cursor_set);
+       WM_operatortype_append(UV_OT_tile_set);
 }
 
 void ED_keymap_uvedit(wmWindowManager *wm)
 {
-       ListBase *keymap= WM_keymap_listbase(wm, "UVEdit", 0, 0);
+       wmKeyMap *keymap;
+       
+       keymap= WM_keymap_find(wm, "UVEdit", 0, 0);
+       keymap->poll= ED_operator_uvedit;
        
+       /* pick selection */
        WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
        RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
-       WM_keymap_add_item(keymap, "UV_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
-       // XXX not working?
-       RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, KM_ALT)->ptr, "extend", 1);
+       WM_keymap_add_item(keymap, "UV_OT_select_loop", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_loop", SELECTMOUSE, KM_PRESS, KM_SHIFT|KM_ALT, 0)->ptr, "extend", 1);
 
-       /* generates event, needs to be after select to work */
-       WM_keymap_add_item(keymap, "WM_OT_tweak_gesture", SELECTMOUSE, KM_PRESS, 0, 0);
+       /* border/circle selection */
+       WM_keymap_add_item(keymap, "UV_OT_select_border", BKEY, KM_PRESS, 0, 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select_border", BKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "pinned", 1);
+       WM_keymap_add_item(keymap, "UV_OT_circle_select", CKEY, KM_PRESS, 0, 0);
 
+       /* selection manipulation */
        WM_keymap_add_item(keymap, "UV_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
        WM_keymap_add_item(keymap, "UV_OT_unlink_selection", LKEY, KM_PRESS, KM_ALT, 0);
-       WM_keymap_add_item(keymap, "UV_OT_de_select_all", AKEY, KM_PRESS, 0, 0);
-       WM_keymap_add_item(keymap, "UV_OT_select_invert", IKEY, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_add_item(keymap, "UV_OT_select_all_toggle", AKEY, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "UV_OT_select_inverse", IKEY, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_add_item(keymap, "UV_OT_select_pinned", PKEY, KM_PRESS, KM_SHIFT, 0);
 
+       /* uv operations */
        WM_keymap_add_item(keymap, "UV_OT_stitch", VKEY, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "UV_OT_pin", PKEY, KM_PRESS, 0, 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_pin", PKEY, KM_PRESS, KM_ALT, 0)->ptr, "clear", 1);
+
+       /* unwrap */
+       WM_keymap_add_item(keymap, "UV_OT_unwrap", EKEY, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "UV_OT_minimize_stretch", VKEY, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_add_item(keymap, "UV_OT_pack_islands", PKEY, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_add_item(keymap, "UV_OT_average_islands_scale", AKEY, KM_PRESS, KM_CTRL, 0);
+
+       /* hide */
+       WM_keymap_add_item(keymap, "UV_OT_hide", HKEY, KM_PRESS, 0, 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_hide", HKEY, KM_PRESS, KM_SHIFT, 0)->ptr, "unselected", 1);
+       WM_keymap_add_item(keymap, "UV_OT_reveal", HKEY, KM_PRESS, KM_ALT, 0);
+
+       /* cursor */
+       WM_keymap_add_item(keymap, "UV_OT_cursor_set", ACTIONMOUSE, KM_PRESS, 0, 0);
+       WM_keymap_add_item(keymap, "UV_OT_tile_set", ACTIONMOUSE, KM_PRESS, KM_SHIFT, 0);
 
        transform_keymap_for_space(wm, keymap, SPACE_IMAGE);
 }