Fix #19382: crash on uv edit stitch, tweaking limit property in tool area.
[blender-staging.git] / source / blender / editors / uvedit / uvedit_ops.c
index e097511e46644278e59356a1b40589a7e093b60c..9216cfb5cdc96bdcf0afff545517a3d162d4a99b 100644 (file)
@@ -28,6 +28,7 @@
  */
 
 #include <stdlib.h>
+#include <string.h>
 #include <math.h>
 
 #include "MEM_guardedalloc.h"
 #include "BKE_image.h"
 #include "BKE_library.h"
 #include "BKE_mesh.h"
+#include "BKE_report.h"
 #include "BKE_utildefines.h"
 
-#include "IMB_imbuf_types.h" // XXX remove?
-
+#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 "WM_api.h"
 #include "WM_types.h"
 
-#include "uvedit_intern.h"
+#include "UI_view2d.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 select_edgeloop_tface_uv(bContext *C, Scene *scene, Image *ima, Object *obedit, EditFace *startefa, int starta, int shift, int *flush);
-void select_linked_tface_uv(bContext *C, Scene *scene, Image *ima, Object *obedit, int mode);
-void uvface_setsel__internal(bContext *C, SpaceImage *sima, Scene *scene, Object *obedit, short select);
+#include "uvedit_intern.h"
 
 /************************* state testing ************************/
 
-int uvedit_test_silent(Object *obedit)
+int ED_uvedit_test(Object *obedit)
 {
-       if(obedit->type != OB_MESH)
-               return 0;
-
-       return EM_texFaceCheck(((Mesh*)obedit->data)->edit_mesh);
-}
+       EditMesh *em;
+       int ret;
 
-int uvedit_test(Object *obedit)
-{
-       // XXX if(!obedit)
-       // XXX  error("Enter Edit Mode to perform this action");
+       if(!obedit || obedit->type != OB_MESH)
+               return 0;
 
-       return 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 ************************/
@@ -98,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))
@@ -108,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)) {
@@ -127,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);
                        }
@@ -143,75 +138,67 @@ 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 || !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);
 }
 
-/*********************** connection testing *********************/
+/*********************** space conversion *********************/
 
-static void uvedit_connection_limit(bContext *C, float *limit, float pixellimit)
+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;
        }
 
-       limit[0]= pixellimit/width;
-       limit[1]= pixellimit/height;
+       dist[0]= pixeldist/width;
+       dist[1]= pixeldist/height;
 }
 
 /*************** visibility and selection utilities **************/
 
 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));
@@ -219,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);
@@ -227,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));
@@ -235,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);
@@ -243,16 +236,75 @@ 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);
 }
 
+int uvedit_edge_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
+{
+       ToolSettings *ts= scene->toolsettings;
+       int nvert= (efa->v4)? 4: 3;
+
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               if(ts->selectmode == SCE_SELECT_FACE)
+                       return (efa->f & SELECT);
+               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));
+       }
+       else
+               return (tf->flag & TF_SEL_MASK(i)) && (tf->flag & TF_SEL_MASK((i+1)%nvert));
+}
+
+void uvedit_edge_select(Scene *scene, EditFace *efa, MTFace *tf, int i)
+{
+       ToolSettings *ts= scene->toolsettings;
+       int nvert= (efa->v4)? 4: 3;
+
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               if(ts->selectmode == SCE_SELECT_FACE)
+                       EM_select_face(efa, 1);
+               else if(ts->selectmode == SCE_SELECT_EDGE)
+                       EM_select_edge((*(&efa->e1 + i)), 1);
+               else {
+                       (efa->v1 + i)->f |= SELECT;
+                       (efa->v1 + (i+1)%nvert)->f |= SELECT;
+               }
+       }
+       else
+               tf->flag |= TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert);
+}
+
+void uvedit_edge_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i)
+{
+       ToolSettings *ts= scene->toolsettings;
+       int nvert= (efa->v4)? 4: 3;
+
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               if(ts->selectmode == SCE_SELECT_FACE)
+                       EM_select_face(efa, 0);
+               else if(ts->selectmode == SCE_SELECT_EDGE)
+                       EM_select_edge((*(&efa->e1 + i)), 0);
+               else {
+                       (efa->v1 + i)->f &= ~SELECT;
+                       (efa->v1 + (i+1)%nvert)->f &= ~SELECT;
+               }
+       }
+       else
+               tf->flag &= ~(TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert));
+}
+
 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;
@@ -263,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;
@@ -275,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;
@@ -324,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;
@@ -341,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];
@@ -375,1091 +432,1902 @@ 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;
 }
 
-/************************** constraints ****************************/
+/************************** find nearest ****************************/
 
-void uvedit_constrain_square(Scene *scene, Image *ima, EditMesh *em)
-{
+typedef struct NearestHit {
        EditFace *efa;
        MTFace *tf;
 
-       /* if 1 vertex selected: doit (with the selected vertex) */
-       for(efa= em->faces.first; efa; efa= efa->next) {
-               if(efa->v4) {
-                       tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+       int vert, uv;
+       int edge, vert2;
+} NearestHit;
 
-                       if(uvedit_face_visible(scene, ima, efa, tf)) {
-                               if(uvedit_uv_selected(scene, efa, tf, 0)) {
-                                       if(tf->uv[1][0] == tf->uv[2][0] ) {
-                                               tf->uv[1][1]= tf->uv[0][1];
-                                               tf->uv[3][0]= tf->uv[0][0];
-                                       }
-                                       else {  
-                                               tf->uv[1][0]= tf->uv[0][0];
-                                               tf->uv[3][1]= tf->uv[0][1];
-                                       }
-                                       
-                               }
+static void find_nearest_uv_edge(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
+{
+       MTFace *tf;
+       EditFace *efa;
+       EditVert *eve;
+       float mindist, dist;
+       int i, nverts;
 
-                               if(uvedit_uv_selected(scene, efa, tf, 1)) {
-                                       if(tf->uv[2][1] == tf->uv[3][1] ) {
-                                               tf->uv[2][0]= tf->uv[1][0];
-                                               tf->uv[0][1]= tf->uv[1][1];
-                                       }
-                                       else {
-                                               tf->uv[2][1]= tf->uv[1][1];
-                                               tf->uv[0][0]= tf->uv[1][0];
-                                       }
+       mindist= 1e10f;
+       memset(hit, 0, sizeof(*hit));
 
-                               }
+       for(i=0, eve=em->verts.first; eve; eve=eve->next, i++)
+               eve->tmp.l = i;
+       
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 
-                               if(uvedit_uv_selected(scene, efa, tf, 2)) {
-                                       if(tf->uv[3][0] == tf->uv[0][0] ) {
-                                               tf->uv[3][1]= tf->uv[2][1];
-                                               tf->uv[1][0]= tf->uv[2][0];
-                                       }
-                                       else {
-                                               tf->uv[3][0]= tf->uv[2][0];
-                                               tf->uv[1][1]= tf->uv[2][1];
-                                       }
-                               }
+               if(uvedit_face_visible(scene, ima, efa, tf)) {
+                       nverts= efa->v4? 4: 3;
 
-                               if(uvedit_uv_selected(scene, efa, tf, 3)) {
-                                       if(tf->uv[0][1] == tf->uv[1][1] ) {
-                                               tf->uv[0][0]= tf->uv[3][0];
-                                               tf->uv[2][1]= tf->uv[3][1];
-                                       }
-                                       else  {
-                                               tf->uv[0][1]= tf->uv[3][1];
-                                               tf->uv[2][0]= tf->uv[3][0];
-                                       }
+                       for(i=0; i<nverts; i++) {
+                               dist= PdistVL2Dfl(co, tf->uv[i], tf->uv[(i+1)%nverts]);
+
+                               if(dist < mindist) {
+                                       hit->tf= tf;
+                                       hit->efa= efa;
+                                       hit->edge= i;
+                                       mindist= dist;
+
+                                       hit->vert= (*(&efa->v1 + i))->tmp.l;
+                                       hit->vert2= (*(&efa->v1 + ((i+1)%nverts)))->tmp.l;
                                }
                        }
                }
        }
 }
 
-/* ******************** 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)
+static void find_nearest_uv_face(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
 {
-       float mat[3][3];
-       int axis;
+       MTFace *tf;
+       EditFace *efa;
+       float mindist, dist, cent[2];
+       int i, nverts;
+
+       mindist= 1e10f;
+       memset(hit, 0, sizeof(*hit));
        
-       Mat3One(mat);
-       axis= RNA_enum_get(op->ptr, "axis");
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 
-       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(); */
-       }
+               if(uvedit_face_visible(scene, ima, efa, tf)) {
+                       nverts= efa->v4? 4: 3;
+                       cent[0]= cent[1]= 0.0f;
 
-       return OPERATOR_FINISHED;
+                       for(i=0; i<nverts; i++) {
+                               cent[0] += tf->uv[i][0];
+                               cent[1] += tf->uv[i][1];
+                       }
+
+                       cent[0] /= nverts;
+                       cent[1] /= nverts;
+                       dist= fabs(co[0]- cent[0]) + fabs(co[1]- cent[1]);
+
+                       if(dist < mindist) {
+                               hit->tf= tf;
+                               hit->efa= efa;
+                               mindist= dist;
+                       }
+               }
+       }
 }
 
-void UV_OT_mirror(wmOperatorType *ot)
+static int nearest_uv_between(MTFace *tf, int nverts, int id, float co[2], float uv[2])
 {
-       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}};
+       float m[3], v1[3], v2[3], c1, c2;
+       int id1, id2;
 
-       /* 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;
+       id1= (id+nverts-1)%nverts;
+       id2= (id+nverts+1)%nverts;
 
-       /* properties */
-       RNA_def_enum(ot->srna, "axis", axis_items, 'x', "Axis", "Axis to mirror UV locations over.");
-}
+       m[0]= co[0]-uv[0];
+       m[1]= co[1]-uv[1];
+       Vec2Subf(v1, tf->uv[id1], tf->uv[id]);
+       Vec2Subf(v2, tf->uv[id2], tf->uv[id]);
 
-/* ******************** align operator **************** */
+       /* m and v2 on same side of v-v1? */
+       c1= v1[0]*m[1] - v1[1]*m[0];
+       c2= v1[0]*v2[1] - v1[1]*v2[0];
 
-/* XXX */
-#if 0
-void weld_align_menu_tface_uv(bContext *C)
-{
-       short mode= 0;
+       if(c1*c2 < 0.0f)
+               return 0;
 
-       mode= pupmenu("Weld/Align%t|Weld%x1|Align Auto%x2|Align X%x3|Align Y%x4");
+       /* m and v1 on same side of v-v2? */
+       c1= v2[0]*m[1] - v2[1]*m[0];
+       c2= v2[0]*v1[1] - v2[1]*v1[0];
 
-       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');
+       return (c1*c2 >= 0.0f);
 }
-#endif
 
-static void weld_align_uv(bContext *C, int tool)
+static void find_nearest_uv_vert(Scene *scene, Image *ima, EditMesh *em, float co[2], float penalty[2], NearestHit *hit)
 {
-       Scene *scene;
-       Object *obedit;
-       Image *ima;
-       EditMesh *em;
        EditFace *efa;
+       EditVert *eve;
        MTFace *tf;
-       float cent[2], min[2], max[2];
+       float mindist, dist;
+       int i, nverts;
+
+       mindist= 1e10f;
+       memset(hit, 0, sizeof(*hit));
        
-       scene= CTX_data_scene(C);
-       obedit= CTX_data_edit_object(C);
-       em= ((Mesh*)obedit->data)->edit_mesh;
-       ima= CTX_data_edit_image(C);
+       for(i=0, eve=em->verts.first; eve; eve=eve->next, i++)
+               eve->tmp.l = i;
+       
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 
-       INIT_MINMAX2(min, max);
+               if(uvedit_face_visible(scene, ima, efa, tf)) {
+                       nverts= efa->v4? 4: 3;
 
-       if(tool == 'a') {
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                       for(i=0; i<nverts; i++) {
+                               if(penalty && uvedit_uv_selected(scene, efa, tf, i))
+                                       dist= fabs(co[0]-tf->uv[i][0])+penalty[0] + fabs(co[1]-tf->uv[i][1])+penalty[1];
+                               else
+                                       dist= fabs(co[0]-tf->uv[i][0]) + fabs(co[1]-tf->uv[i][1]);
 
-                       if(uvedit_face_visible(scene, ima, efa, tf)) {
-                               if(uvedit_uv_selected(scene, efa, tf, 0))
-                                       DO_MINMAX2(tf->uv[0], min, max)
-                               if(uvedit_uv_selected(scene, efa, tf, 1))
-                                       DO_MINMAX2(tf->uv[1], min, max)
-                               if(uvedit_uv_selected(scene, efa, tf, 2))
-                                       DO_MINMAX2(tf->uv[2], min, max)
-                               if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
-                                       DO_MINMAX2(tf->uv[3], min, max)
-                       }
-               }
+                               if(dist<=mindist) {
+                                       if(dist==mindist)
+                                               if(!nearest_uv_between(tf, nverts, i, co, tf->uv[i]))
+                                                       continue;
 
-               tool= (max[0]-min[0] >= max[1]-min[1])? 'y': 'x';
-       }
+                                       mindist= dist;
 
-       uvedit_center(scene, ima, obedit, cent, 0);
+                                       hit->uv= i;
+                                       hit->tf= tf;
+                                       hit->efa= efa;
 
-       if(tool == 'x' || tool == 'w') {
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                       if(uvedit_face_visible(scene, ima, efa, tf)) {
-                               if(uvedit_uv_selected(scene, efa, tf, 0))
-                                       tf->uv[0][0]= cent[0];
-                               if(uvedit_uv_selected(scene, efa, tf, 1))
-                                       tf->uv[1][0]= cent[0];
-                               if(uvedit_uv_selected(scene, efa, tf, 2))
-                                       tf->uv[2][0]= cent[0];
-                               if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
-                                       tf->uv[3][0]= cent[0];
+                                       hit->vert= (*(&efa->v1 + i))->tmp.l;
+                               }
                        }
                }
        }
+}
 
-       if(tool == 'y' || tool == 'w') {
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                       if(uvedit_face_visible(scene, ima, efa, tf)) {
-                               if(uvedit_uv_selected(scene, efa, tf, 0))
-                                       tf->uv[0][1]= cent[1];
-                               if(uvedit_uv_selected(scene, efa, tf, 1))
-                                       tf->uv[1][1]= cent[1];
-                               if(uvedit_uv_selected(scene, efa, tf, 2))
-                                       tf->uv[2][1]= cent[1];
-                               if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
-                                       tf->uv[3][1]= cent[1];
+int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, float co[2], float uv[2])
+{
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+       EditFace *efa;
+       MTFace *tf;
+       float mindist, dist;
+       int i, nverts, found= 0;
+
+       mindist= 1e10f;
+       uv[0]= co[0];
+       uv[1]= co[1];
+       
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+               if(uvedit_face_visible(scene, ima, efa, tf)) {
+                       nverts= efa->v4? 4: 3;
+
+                       for(i=0; i<nverts; i++) {
+                               dist= fabs(co[0]-tf->uv[i][0]) + fabs(co[1]-tf->uv[i][1]);
+
+                               if(dist<=mindist) {
+                                       mindist= dist;
+
+                                       uv[0]= tf->uv[i][0];
+                                       uv[1]= tf->uv[i][1];
+                                       found= 1;
+                               }
                        }
                }
        }
 
-       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); // XXX
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return found;
 }
 
-static int align_exec(bContext *C, wmOperator *op)
+/*********************** loop select ***********************/
+
+static void uv_vertex_loop_flag(UvMapVert *first)
 {
-       weld_align_uv(C, RNA_enum_get(op->ptr, "axis"));
+       UvMapVert *iterv;
+       int count= 0;
 
-       return OPERATOR_FINISHED;
+       for(iterv=first; iterv; iterv=iterv->next) {
+               if(iterv->separate && iterv!=first)
+                       break;
+
+               count++;
+       }
+       
+       if(count < 5)
+               first->flag= 1;
 }
 
-void UV_OT_align(wmOperatorType *ot)
+static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, EditFace *efa, int a)
 {
-       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}};
-
-       /* identifiers */
-       ot->name= "Align";
-       ot->idname= "UV_OT_align";
-       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       UvMapVert *iterv, *first;
        
-       /* api callbacks */
-       ot->exec= align_exec;
-       ot->poll= ED_operator_uvedit;
+       first= EM_get_uv_map_vert(vmap, (*(&efa->v1 + a))->tmp.l);
 
-       /* properties */
-       RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on.");
+       for(iterv=first; iterv; iterv=iterv->next) {
+               if(iterv->separate)
+                       first= iterv;
+               if(iterv->f == efa->tmp.l)
+                       return first;
+       }
+       
+       return NULL;
 }
 
-/* ******************** weld operator **************** */
+static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface)
+{
+       UvMapVert *iterv1, *iterv2;
+       EditFace *efa;
+       int tot = 0;
+
+       /* count number of faces this edge has */
+       for(iterv1=first1; iterv1; iterv1=iterv1->next) {
+               if(iterv1->separate && iterv1 != first1)
+                       break;
+
+               for(iterv2=first2; iterv2; iterv2=iterv2->next) {
+                       if(iterv2->separate && iterv2 != first2)
+                               break;
+
+                       if(iterv1->f == iterv2->f) {
+                               /* if face already tagged, don't do this edge */
+                               efa= EM_get_face_for_index(iterv1->f);
+                               if(efa->f1)
+                                       return 0;
+
+                               tot++;
+                               break;
+                       }
+               }
+       }
+
+       if(*totface == 0) /* start edge */
+               *totface= tot;
+       else if(tot != *totface) /* check for same number of faces as start edge */
+               return 0;
+
+       /* tag the faces */
+       for(iterv1=first1; iterv1; iterv1=iterv1->next) {
+               if(iterv1->separate && iterv1 != first1)
+                       break;
+
+               for(iterv2=first2; iterv2; iterv2=iterv2->next) {
+                       if(iterv2->separate && iterv2 != first2)
+                               break;
+
+                       if(iterv1->f == iterv2->f) {
+                               efa= EM_get_face_for_index(iterv1->f);
+                               efa->f1= 1;
+                               break;
+                       }
+               }
+       }
+
+       return 1;
+}
+
+static int select_edgeloop(Scene *scene, Image *ima, EditMesh *em, NearestHit *hit, float limit[2], int extend)
+{
+       EditVert *eve;
+       EditFace *efa;
+       MTFace *tf;
+       UvVertMap *vmap;
+       UvMapVert *iterv1, *iterv2;
+       int a, count, looking, nverts, starttotf, select;
+
+       /* setup */
+       EM_init_index_arrays(em, 0, 0, 1);
+       vmap= EM_make_uv_vert_map(em, 0, 0, limit);
+
+       for(count=0, eve=em->verts.first; eve; count++, eve= eve->next)
+               eve->tmp.l = count;
+
+       for(count=0, efa= em->faces.first; efa; count++, efa= efa->next) {
+               if(!extend) {
+                       tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                       uvedit_face_deselect(scene, efa, tf);
+               }
+
+               efa->tmp.l= count;
+               efa->f1= 0;
+       }
+       
+       /* set flags for first face and verts */
+       nverts= (hit->efa->v4)? 4: 3;
+       iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge);
+       iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts);
+       uv_vertex_loop_flag(iterv1);
+       uv_vertex_loop_flag(iterv2);
+
+       starttotf= 0;
+       uv_edge_tag_faces(iterv1, iterv2, &starttotf);
+
+       /* sorry, first edge isnt even ok */
+       if(iterv1->flag==0 && iterv2->flag==0) looking= 0;
+       else looking= 1;
+
+       /* iterate */
+       while(looking) {
+               looking= 0;
+
+               /* find correct valence edges which are not tagged yet, but connect to tagged one */
+               for(efa= em->faces.first; efa; efa=efa->next) {
+                       tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+                       if(!efa->f1 && uvedit_face_visible(scene, ima, efa, tf)) {
+                               nverts= (efa->v4)? 4: 3;
+                               for(a=0; a<nverts; a++) {
+                                       /* check face not hidden and not tagged */
+                                       iterv1= uv_vertex_map_get(vmap, efa, a);
+                                       iterv2= uv_vertex_map_get(vmap, efa, (a+1)%nverts);
+
+                                       /* check if vertex is tagged and has right valence */
+                                       if(iterv1->flag || iterv2->flag) {
+                                               if(uv_edge_tag_faces(iterv1, iterv2, &starttotf)) {
+                                                       looking= 1;
+                                                       efa->f1= 1;
+
+                                                       uv_vertex_loop_flag(iterv1);
+                                                       uv_vertex_loop_flag(iterv2);
+                                                       break;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* do the actual select/deselect */
+       nverts= (hit->efa->v4)? 4: 3;
+       iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge);
+       iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts);
+       iterv1->flag= 1;
+       iterv2->flag= 1;
+
+       if(extend) {
+               tf= CustomData_em_get(&em->fdata, hit->efa->data, CD_MTFACE);
+
+               if(uvedit_uv_selected(scene, hit->efa, tf, hit->edge) && uvedit_uv_selected(scene, hit->efa, tf, hit->edge))
+                       select= 0;
+               else
+                       select= 1;
+       }
+       else
+               select= 1;
+       
+       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(a=0; a<nverts; a++) {
+                       iterv1= uv_vertex_map_get(vmap, efa, a);
+
+                       if(iterv1->flag) {
+                               if(select) uvedit_uv_select(scene, efa, tf, a);
+                               else uvedit_uv_deselect(scene, efa, tf, a);
+                       }
+               }
+       }
+
+       /* cleanup */
+       EM_free_uv_vert_map(vmap);
+       EM_free_index_arrays();
+
+       return (select)? 1: -1;
+}
+
+/*********************** linked select ***********************/
+
+static void select_linked(Scene *scene, Image *ima, EditMesh *em, float limit[2], NearestHit *hit, int extend)
+{
+       EditFace *efa;
+       MTFace *tf;
+       UvVertMap *vmap;
+       UvMapVert *vlist, *iterv, *startv;
+       int a, i, nverts, j, stacksize= 0, *stack;
+       char *flag;
+
+       vmap= EM_make_uv_vert_map(em, 1, 1, limit);
+       if(vmap == NULL)
+               return;
+
+       stack= MEM_mallocN(sizeof(*stack)* BLI_countlist(&em->faces), "UvLinkStack");
+       flag= MEM_callocN(sizeof(*flag)*BLI_countlist(&em->faces), "UvLinkFlag");
+
+       if(!hit) {
+               for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
+                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+                       if(uvedit_face_visible(scene, ima, efa, tf)) {
+                               if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) {
+                                       stack[stacksize]= a;
+                                       stacksize++;
+                                       flag[a]= 1;
+                               }
+                       }
+               }
+       }
+       else {
+               for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
+                       if(efa == hit->efa) {
+                               stack[stacksize]= a;
+                               stacksize++;
+                               flag[a]= 1;
+                               break;
+                       }
+               }
+       }
+
+       while(stacksize > 0) {
+               stacksize--;
+               a= stack[stacksize];
+               
+               for(j=0, efa= em->faces.first; efa; efa= efa->next, j++)
+                       if(j==a)
+                               break;
+
+               nverts= efa->v4? 4: 3;
+
+               for(i=0; i<nverts; i++) {
+                       /* make_uv_vert_map_EM sets verts tmp.l to the indicies */
+                       vlist= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l);
+                       
+                       startv= vlist;
+
+                       for(iterv=vlist; iterv; iterv=iterv->next) {
+                               if(iterv->separate)
+                                       startv= iterv;
+                               if(iterv->f == a)
+                                       break;
+                       }
+
+                       for(iterv=startv; iterv; iterv=iterv->next) {
+                               if((startv != iterv) && (iterv->separate))
+                                       break;
+                               else if(!flag[iterv->f]) {
+                                       flag[iterv->f]= 1;
+                                       stack[stacksize]= iterv->f;;
+                                       stacksize++;
+                               }
+                       }
+               }
+       }
+
+       if(!extend || hit) {
+               for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
+                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                       if(flag[a])
+                               tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+                       else
+                               tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+               }
+       }
+       else if(extend && hit) {
+               for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
+                       if(flag[a]) {
+                               tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                               if(efa->v4) {
+                                       if((tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)))
+                                               break;
+                               }
+                               else if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
+                                       break;
+                       }
+               }
+
+               if(efa) {
+                       for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
+                               if(flag[a]) {
+                                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                                       tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+                               }
+                       }
+               }
+               else {
+                       for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
+                               if(flag[a]) {
+                                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                                       tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+                               }
+                       }
+               }
+       }
+       
+       MEM_freeN(stack);
+       MEM_freeN(flag);
+       EM_free_uv_vert_map(vmap);
+}
+
+/* ******************** align operator **************** */
+
+static void weld_align_uv(bContext *C, int tool)
+{
+       Scene *scene;
+       Object *obedit;
+       Image *ima;
+       EditMesh *em;
+       EditFace *efa;
+       MTFace *tf;
+       float cent[2], min[2], max[2];
+       
+       scene= CTX_data_scene(C);
+       obedit= CTX_data_edit_object(C);
+       em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+       ima= CTX_data_edit_image(C);
+
+       INIT_MINMAX2(min, max);
+
+       if(tool == 'a') {
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+                       if(uvedit_face_visible(scene, ima, efa, tf)) {
+                               if(uvedit_uv_selected(scene, efa, tf, 0))
+                                       DO_MINMAX2(tf->uv[0], min, max)
+                               if(uvedit_uv_selected(scene, efa, tf, 1))
+                                       DO_MINMAX2(tf->uv[1], min, max)
+                               if(uvedit_uv_selected(scene, efa, tf, 2))
+                                       DO_MINMAX2(tf->uv[2], min, max)
+                               if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
+                                       DO_MINMAX2(tf->uv[3], min, max)
+                       }
+               }
+
+               tool= (max[0]-min[0] >= max[1]-min[1])? 'y': 'x';
+       }
+
+       uvedit_center(scene, ima, obedit, cent, 0);
+
+       if(tool == 'x' || tool == 'w') {
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                       if(uvedit_face_visible(scene, ima, efa, tf)) {
+                               if(uvedit_uv_selected(scene, efa, tf, 0))
+                                       tf->uv[0][0]= cent[0];
+                               if(uvedit_uv_selected(scene, efa, tf, 1))
+                                       tf->uv[1][0]= cent[0];
+                               if(uvedit_uv_selected(scene, efa, tf, 2))
+                                       tf->uv[2][0]= cent[0];
+                               if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
+                                       tf->uv[3][0]= cent[0];
+                       }
+               }
+       }
+
+       if(tool == 'y' || tool == 'w') {
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                       if(uvedit_face_visible(scene, ima, efa, tf)) {
+                               if(uvedit_uv_selected(scene, efa, tf, 0))
+                                       tf->uv[0][1]= cent[1];
+                               if(uvedit_uv_selected(scene, efa, tf, 1))
+                                       tf->uv[1][1]= cent[1];
+                               if(uvedit_uv_selected(scene, efa, tf, 2))
+                                       tf->uv[2][1]= cent[1];
+                               if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
+                                       tf->uv[3][1]= cent[1];
+                       }
+               }
+       }
+
+       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)
+{
+       weld_align_uv(C, RNA_enum_get(op->ptr, "axis"));
+
+       return OPERATOR_FINISHED;
+}
+
+void UV_OT_align(wmOperatorType *ot)
+{
+       static EnumPropertyItem axis_items[] = {
+               {'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;
+       
+       /* api callbacks */
+       ot->exec= align_exec;
+       ot->poll= ED_operator_uvedit;
+
+       /* properties */
+       RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on.");
+}
+
+/* ******************** weld operator **************** */
+
+static int weld_exec(bContext *C, wmOperator *op)
+{
+       weld_align_uv(C, 'w');
+
+       return OPERATOR_FINISHED;
+}
+
+void UV_OT_weld(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Weld";
+       ot->idname= "UV_OT_weld";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* api callbacks */
+       ot->exec= weld_exec;
+       ot->poll= ED_operator_uvedit;
+}
+
+/* ******************** stitch operator **************** */
+
+/* just for averaging UVs */
+typedef struct UVVertAverage {
+       float uv[2];
+       int count;
+} UVVertAverage;
+
+static int stitch_exec(bContext *C, wmOperator *op)
+{
+       SpaceImage *sima;
+       Scene *scene;
+       Object *obedit;
+       EditMesh *em;
+       EditFace *efa;
+       EditVert *eve;
+       Image *ima;
+       MTFace *tf;
+       
+       sima= CTX_wm_space_image(C);
+       scene= CTX_data_scene(C);
+       obedit= CTX_data_edit_object(C);
+       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];
+               int a, vtot;
+
+               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) {
+                       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);
+
+                       while(vlist) {
+                               newuv[0]= 0; newuv[1]= 0;
+                               vtot= 0;
+
+                               for(iterv=vlist; iterv; iterv=iterv->next) {
+                                       if((iterv != vlist) && iterv->separate)
+                                               break;
+
+                                       efa = EM_get_face_for_index(iterv->f);
+                                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                                       
+                                       if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) {
+                                               newuv[0] += tf->uv[iterv->tfindex][0];
+                                               newuv[1] += tf->uv[iterv->tfindex][1];
+                                               vtot++;
+                                       }
+                               }
+
+                               if(vtot > 1) {
+                                       newuv[0] /= vtot; newuv[1] /= vtot;
+
+                                       for(iterv=vlist; iterv; iterv=iterv->next) {
+                                               if((iterv != vlist) && iterv->separate)
+                                                       break;
+
+                                               efa = EM_get_face_for_index(iterv->f);
+                                               tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+                                               if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) {
+                                                       tf->uv[iterv->tfindex][0]= newuv[0];
+                                                       tf->uv[iterv->tfindex][1]= newuv[1];
+                                               }
+                                       }
+                               }
+
+                               vlist= iterv;
+                       }
+               }
+
+               EM_free_uv_vert_map(vmap);
+               EM_free_index_arrays();
+       }
+       else {
+               UVVertAverage *uv_average, *uvav;
+               int count;
+
+               // index and count verts
+               for(count=0, eve=em->verts.first; eve; count++, eve= eve->next)
+                       eve->tmp.l = count;
+               
+               uv_average= MEM_callocN(sizeof(UVVertAverage)*count, "Stitch");
+               
+               // gather uv averages per vert
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+                       if(uvedit_face_visible(scene, ima, efa, tf)) {
+                               if(uvedit_uv_selected(scene, efa, tf, 0)) {
+                                       uvav = uv_average + efa->v1->tmp.l;
+                                       uvav->count++;
+                                       uvav->uv[0] += tf->uv[0][0];
+                                       uvav->uv[1] += tf->uv[0][1];
+                               }
+
+                               if(uvedit_uv_selected(scene, efa, tf, 1)) {
+                                       uvav = uv_average + efa->v2->tmp.l;
+                                       uvav->count++;
+                                       uvav->uv[0] += tf->uv[1][0];
+                                       uvav->uv[1] += tf->uv[1][1];
+                               }
+
+                               if(uvedit_uv_selected(scene, efa, tf, 2)) {
+                                       uvav = uv_average + efa->v3->tmp.l;
+                                       uvav->count++;
+                                       uvav->uv[0] += tf->uv[2][0];
+                                       uvav->uv[1] += tf->uv[2][1];
+                               }
+
+                               if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
+                                       uvav = uv_average + efa->v4->tmp.l;
+                                       uvav->count++;
+                                       uvav->uv[0] += tf->uv[3][0];
+                                       uvav->uv[1] += tf->uv[3][1];
+                               }
+                       }
+               }
+               
+               // apply uv welding
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+                       if(uvedit_face_visible(scene, ima, efa, tf)) {
+                               if(uvedit_uv_selected(scene, efa, tf, 0)) {
+                                       uvav = uv_average + efa->v1->tmp.l;
+                                       tf->uv[0][0] = uvav->uv[0]/uvav->count;
+                                       tf->uv[0][1] = uvav->uv[1]/uvav->count;
+                               }
+
+                               if(uvedit_uv_selected(scene, efa, tf, 1)) {
+                                       uvav = uv_average + efa->v2->tmp.l;
+                                       tf->uv[1][0] = uvav->uv[0]/uvav->count;
+                                       tf->uv[1][1] = uvav->uv[1]/uvav->count;
+                               }
+
+                               if(uvedit_uv_selected(scene, efa, tf, 2)) {
+                                       uvav = uv_average + efa->v3->tmp.l;
+                                       tf->uv[2][0] = uvav->uv[0]/uvav->count;
+                                       tf->uv[2][1] = uvav->uv[1]/uvav->count;
+                               }
+
+                               if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
+                                       uvav = uv_average + efa->v4->tmp.l;
+                                       tf->uv[3][0] = uvav->uv[0]/uvav->count;
+                                       tf->uv[3][1] = uvav->uv[1]/uvav->count;
+                               }
+                       }
+               }
+
+               MEM_freeN(uv_average);
+       }
+
+       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;
+}
+
+void UV_OT_stitch(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Stitch";
+       ot->idname= "UV_OT_stitch";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* api callbacks */
+       ot->exec= stitch_exec;
+       ot->poll= ED_operator_uvedit;
+
+       /* properties */
+       RNA_def_boolean(ot->srna, "use_limit", 1, "Use Limit", "Stitch UVs within a specified limit distance.");
+       RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit", "Limit distance in normalized coordinates.", -FLT_MAX, FLT_MAX);
+}
 
-static int weld_exec(bContext *C, wmOperator *op)
+/* ******************** (de)select all operator **************** */
+
+static int select_inverse_exec(bContext *C, wmOperator *op)
 {
-       weld_align_uv(C, 'w');
+       Scene *scene;
+       ToolSettings *ts;
+       Object *obedit;
+       EditMesh *em;
+       EditFace *efa;
+       Image *ima;
+       MTFace *tf;
+       
+       scene= CTX_data_scene(C);
+       ts= CTX_data_tool_settings(C);
+       obedit= CTX_data_edit_object(C);
+       em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+       ima= CTX_data_edit_image(C);
+
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               EM_select_swap(em);
+       }
+       else {
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+                       if(uvedit_face_visible(scene, ima, efa, tf)) {
+                               tf->flag ^= TF_SEL1;
+                               tf->flag ^= TF_SEL2;
+                               tf->flag ^= TF_SEL3;
+                               if(efa->v4) tf->flag ^= TF_SEL4;
+                       }
+               }
+       }
+
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 
+       BKE_mesh_end_editmesh(obedit->data, em);
        return OPERATOR_FINISHED;
 }
 
-void UV_OT_weld(wmOperatorType *ot)
+void UV_OT_select_inverse(wmOperatorType *ot)
 {
        /* identifiers */
-       ot->name= "Weld";
-       ot->idname= "UV_OT_weld";
-       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= weld_exec;
+       ot->exec= select_inverse_exec;
        ot->poll= ED_operator_uvedit;
 }
 
-/* ******************** stitch operator **************** */
-
-/* just for averaging UVs */
-typedef struct UVVertAverage {
-       float uv[2];
-       int count;
-} UVVertAverage;
+/* ******************** (de)select all operator **************** */
 
-static int stitch_exec(bContext *C, wmOperator *op)
+static int de_select_all_exec(bContext *C, wmOperator *op)
 {
        Scene *scene;
+       ToolSettings *ts;
        Object *obedit;
        EditMesh *em;
        EditFace *efa;
-       EditVert *eve;
        Image *ima;
        MTFace *tf;
+       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(RNA_boolean_get(op->ptr, "use_limit")) {
-               UvVertMap *vmap;
-               UvMapVert *vlist, *iterv;
-               float newuv[2], limit[2], pixels;
-               int a, vtot;
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               EM_toggle_select_all(em);
+       }
+       else {
+               sel= 0;
 
-               pixels= RNA_float_get(op->ptr, "limit");
-               uvedit_connection_limit(C, limit, pixels);
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 
-               EM_init_index_arrays(em, 0, 0, 1);
-               vmap= EM_make_uv_vert_map(em, 1, 0, limit);
+                       if(uvedit_face_visible(scene, ima, efa, tf)) {
+                               if(tf->flag & (TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4)) {
+                                       sel= 1;
+                                       break;
+                               }
+                       }
+               }
+       
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+                       if(uvedit_face_visible(scene, ima, efa, tf)) {
+                               if(efa->v4) {
+                                       if(sel) tf->flag &= ~(TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
+                                       else tf->flag |= (TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
+                               }
+                               else {
+                                       if(sel) tf->flag &= ~(TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
+                                       else tf->flag |= (TF_SEL1+TF_SEL2+TF_SEL3);
+                               }
+                       }
+               }
+       }
+
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;
+}
+
+void UV_OT_select_all_toggle(wmOperatorType *ot)
+{
+       /* identifiers */
+       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;
+       ot->poll= ED_operator_uvedit;
+}
+
+/* ******************** mouse select operator **************** */
+
+static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky)
+{
+       int i;
+
+       /* this function test if some vertex needs to selected
+        * in addition to the existing ones due to sticky select */
+       if(sticky == SI_STICKY_DISABLE)
+               return 0;
+
+       for(i=0; i<4; i++) {
+               if(hitv[i] == v) {
+                       if(sticky == SI_STICKY_LOC) {
+                               if(fabs(hituv[i][0]-uv[0]) < limit[0] && fabs(hituv[i][1]-uv[1]) < limit[1])
+                                       return 1;
+                       }
+                       else if(sticky == SI_STICKY_VERTEX)
+                               return 1;
+               }
+       }
+
+       return 0;
+}
+
+static int mouse_select(bContext *C, float co[2], int extend, int loop)
+{
+       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= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+       EditFace *efa;
+       MTFace *tf;
+       NearestHit hit;
+       int a, i, select = 1, selectmode, sticky, sync, hitv[4], nvert;
+       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(sima, limit, 0.05f);
+       uvedit_pixel_to_float(sima, penalty, 5.0f);
+
+       /* retrieve operation mode */
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               sync= 1;
+
+               if(ts->selectmode & SCE_SELECT_FACE)
+                       selectmode= UV_SELECT_FACE;
+               else if(ts->selectmode & SCE_SELECT_EDGE)
+                       selectmode= UV_SELECT_EDGE;
+               else
+                       selectmode= UV_SELECT_VERTEX;
+
+               sticky= SI_STICKY_DISABLE;
+       }
+       else {
+               sync= 0;
+               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) {
+                       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) {
+                       BKE_mesh_end_editmesh(obedit->data, em);
+                       return OPERATOR_CANCELLED;
+               }
+
+               /* mark 1 vertex as being hit */
+               for(i=0; i<4; i++)
+                       hitv[i]= 0xFFFFFFFF;
 
-               if(vmap == NULL)
+               hitv[hit.uv]= hit.vert;
+               hituv[hit.uv]= hit.tf->uv[hit.uv];
+       }
+       else if(selectmode == UV_SELECT_EDGE) {
+               /* find edge */
+               find_nearest_uv_edge(scene, ima, em, co, &hit);
+               if(hit.efa == 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);
+               /* mark 2 edge vertices as being hit */
+               for(i=0; i<4; i++)
+                       hitv[i]= 0xFFFFFFFF;
 
-                       while(vlist) {
-                               newuv[0]= 0; newuv[1]= 0;
-                               vtot= 0;
+               nvert= (hit.efa->v4)? 4: 3;
 
-                               for(iterv=vlist; iterv; iterv=iterv->next) {
-                                       if((iterv != vlist) && iterv->separate)
-                                               break;
+               hitv[hit.edge]= hit.vert;
+               hitv[(hit.edge+1)%nvert]= hit.vert2;
+               hituv[hit.edge]= hit.tf->uv[hit.edge];
+               hituv[(hit.edge+1)%nvert]= hit.tf->uv[(hit.edge+1)%nvert];
+       }
+       else if(selectmode == UV_SELECT_FACE) {
+               /* find face */
+               find_nearest_uv_face(scene, ima, em, co, &hit);
+               if(hit.efa == NULL) {
+                       BKE_mesh_end_editmesh(obedit->data, em);
+                       return OPERATOR_CANCELLED;
+               }
+               
+               /* make active */
+               EM_set_actFace(em, hit.efa);
 
-                                       efa = EM_get_face_for_index(iterv->f);
-                                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                                       
-                                       if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) {
-                                               newuv[0] += tf->uv[iterv->tfindex][0];
-                                               newuv[1] += tf->uv[iterv->tfindex][1];
-                                               vtot++;
+               /* mark all face vertices as being hit */
+               for(i=0; i<4; i++)
+                       hituv[i]= hit.tf->uv[i];
+
+               hitv[0]= hit.efa->v1->tmp.l;
+               hitv[1]= hit.efa->v2->tmp.l;
+               hitv[2]= hit.efa->v3->tmp.l;
+               
+               if(hit.efa->v4) hitv[3]= hit.efa->v4->tmp.l;
+               else hitv[3]= 0xFFFFFFFF;
+       }
+       else if(selectmode == UV_SELECT_ISLAND) {
+               find_nearest_uv_vert(scene, ima, em, co, NULL, &hit);
+
+               if(hit.efa==NULL) {
+                       BKE_mesh_end_editmesh(obedit->data, em);
+                       return OPERATOR_CANCELLED;
+               }
+       }
+       else {
+               BKE_mesh_end_editmesh(obedit->data, em);
+               return OPERATOR_CANCELLED;
+       }
+
+       /* do selection */
+       if(loop) {
+               flush= select_edgeloop(scene, ima, em, &hit, limit, extend);
+       }
+       else if(selectmode == UV_SELECT_ISLAND) {
+               select_linked(scene, ima, em, limit, &hit, extend);
+       }
+       else if(extend) {
+               if(selectmode == UV_SELECT_VERTEX) {
+                       /* (de)select uv vertex */
+                       if(uvedit_uv_selected(scene, hit.efa, hit.tf, hit.uv)) {
+                               uvedit_uv_deselect(scene, hit.efa, hit.tf, hit.uv);
+                               select= 0;
+                       }
+                       else {
+                               uvedit_uv_select(scene, hit.efa, hit.tf, hit.uv);
+                               select= 1;
+                       }
+                       flush = 1;
+               }
+               else if(selectmode == UV_SELECT_EDGE) {
+                       /* (de)select edge */
+                       if(uvedit_edge_selected(scene, hit.efa, hit.tf, hit.edge)) {
+                               uvedit_edge_deselect(scene, hit.efa, hit.tf, hit.edge);
+                               select= 0;
+                       }
+                       else {
+                               uvedit_edge_select(scene, hit.efa, hit.tf, hit.edge);
+                               select= 1;
+                       }
+                       flush = 1;
+               }
+               else if(selectmode == UV_SELECT_FACE) {
+                       /* (de)select face */
+                       if(uvedit_face_selected(scene, hit.efa, hit.tf)) {
+                               uvedit_face_deselect(scene, hit.efa, hit.tf);
+                               select= 0;
+                       }
+                       else {
+                               uvedit_face_select(scene, hit.efa, hit.tf);
+                               select= 1;
+                       }
+                       flush = -1;
+               }
+
+               /* (de)select sticky uv nodes */
+               if(sticky != SI_STICKY_DISABLE) {
+                       EditVert *ev;
+                       
+                       for(a=0, ev=em->verts.first; ev; ev = ev->next, a++)
+                               ev->tmp.l = a;
+                       
+                       /* deselect */
+                       if(select==0) {
+                               for(efa= em->faces.first; efa; efa= efa->next) {
+                                       tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+
+                                       if(uvedit_face_visible(scene, ima, efa, tf)) {
+                                               if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
+                                                       uvedit_uv_deselect(scene, efa, tf, 0);
+                                               if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
+                                                       uvedit_uv_deselect(scene, efa, tf, 1);
+                                               if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
+                                                       uvedit_uv_deselect(scene, efa, tf, 2);
+                                               if(efa->v4)
+                                                       if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
+                                                               uvedit_uv_deselect(scene, efa, tf, 3);
                                        }
                                }
+                               flush = -1;
+                       }
+                       /* select */
+                       else {
+                               for(efa= em->faces.first; efa; efa= efa->next) {
+                                       tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 
-                               if(vtot > 1) {
-                                       newuv[0] /= vtot; newuv[1] /= vtot;
+                                       if(uvedit_face_visible(scene, ima, efa, tf)) {
+                                               if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
+                                                       uvedit_uv_select(scene, efa, tf, 0);
+                                               if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
+                                                       uvedit_uv_select(scene, efa, tf, 1);
+                                               if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
+                                                       uvedit_uv_select(scene, efa, tf, 2);
+                                               if(efa->v4)
+                                                       if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
+                                                               uvedit_uv_select(scene, efa, tf, 3);
+                                       }
+                               }
+                               
+                               flush = 1;
+                       }                       
+               }
+       }
+       else {
+               /* deselect all */
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                       uvedit_face_deselect(scene, efa, tf);
+               }
+
+               if(selectmode == UV_SELECT_VERTEX) {
+                       /* select vertex */
+                       uvedit_uv_select(scene, hit.efa, hit.tf, hit.uv);
+                       flush= 1;
+               }
+               else if(selectmode == UV_SELECT_EDGE) {
+                       /* select edge */
+                       uvedit_edge_select(scene, hit.efa, hit.tf, hit.edge);
+                       flush= 1;
+               }
+               else if(selectmode == UV_SELECT_FACE) {
+                       /* select face */
+                       uvedit_face_select(scene, hit.efa, hit.tf);
+               }
+
+               /* select sticky uvs */
+               if(sticky != SI_STICKY_DISABLE) {
+                       for(efa= em->faces.first; efa; efa= efa->next) {
+                               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                               if(uvedit_face_visible(scene, ima, efa, tf)) {
+                                       if(sticky == SI_STICKY_DISABLE) continue;
+
+                                       if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
+                                               uvedit_uv_select(scene, efa, tf, 0);
+                                       if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
+                                               uvedit_uv_select(scene, efa, tf, 1);
+                                       if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
+                                               uvedit_uv_select(scene, efa, tf, 2);
+                                       if(efa->v4)
+                                               if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
+                                                       uvedit_uv_select(scene, efa, tf, 3);
+
+                                       flush= 1;
+                               }
+                       }
+               }
+       }
+       
+       if(sync) {
+               /* flush for mesh selection */
+               if(ts->selectmode != SCE_SELECT_FACE) {
+                       if(flush==1)            EM_select_flush(em);
+                       else if(flush==-1)      EM_deselect_flush(em);
+               }
+       }
+       
+       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;
+}
+
+static int select_exec(bContext *C, wmOperator *op)
+{
+       float co[2];
+       int extend, loop;
+
+       RNA_float_get_array(op->ptr, "location", co);
+       extend= RNA_boolean_get(op->ptr, "extend");
+       loop= 0;
+
+       return mouse_select(C, co, extend, loop);
+}
+
+static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       ARegion *ar= CTX_wm_region(C);
+       float co[2];
+       int x, y;
+
+       x= event->x - ar->winrct.xmin;
+       y= event->y - ar->winrct.ymin;
+
+       UI_view2d_region_to_view(&ar->v2d, x, y, &co[0], &co[1]);
+       RNA_float_set_array(op->ptr, "location", co);
 
-                                       for(iterv=vlist; iterv; iterv=iterv->next) {
-                                               if((iterv != vlist) && iterv->separate)
-                                                       break;
+       return select_exec(C, op);
+}
 
-                                               efa = EM_get_face_for_index(iterv->f);
-                                               tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+void UV_OT_select(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select";
+       ot->idname= "UV_OT_select";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* api callbacks */
+       ot->exec= select_exec;
+       ot->invoke= select_invoke;
+       ot->poll= ED_operator_uvedit;
 
-                                               if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) {
-                                                       tf->uv[iterv->tfindex][0]= newuv[0];
-                                                       tf->uv[iterv->tfindex][1]= newuv[1];
-                                               }
-                                       }
-                               }
+       /* properties */
+       RNA_def_boolean(ot->srna, "extend", 0,
+               "Extend", "Extend selection rather than clearing the existing selection.");
+       RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
+               "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds.", -100.0f, 100.0f);
+}
 
-                               vlist= iterv;
-                       }
-               }
+/* ******************** loop select operator **************** */
 
-               EM_free_uv_vert_map(vmap);
-               EM_free_index_arrays();
-       }
-       else {
-               UVVertAverage *uv_average, *uvav;
-               int count;
+static int select_loop_exec(bContext *C, wmOperator *op)
+{
+       float co[2];
+       int extend, loop;
 
-               // index and count verts
-               for(count=0, eve=em->verts.first; eve; count++, eve= eve->next)
-                       eve->tmp.l = count;
-               
-               uv_average= MEM_callocN(sizeof(UVVertAverage)*count, "Stitch");
-               
-               // gather uv averages per vert
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+       RNA_float_get_array(op->ptr, "location", co);
+       extend= RNA_boolean_get(op->ptr, "extend");
+       loop= 1;
 
-                       if(uvedit_face_visible(scene, ima, efa, tf)) {
-                               if(uvedit_uv_selected(scene, efa, tf, 0)) {
-                                       uvav = uv_average + efa->v1->tmp.l;
-                                       uvav->count++;
-                                       uvav->uv[0] += tf->uv[0][0];
-                                       uvav->uv[1] += tf->uv[0][1];
-                               }
+       return mouse_select(C, co, extend, loop);
+}
 
-                               if(uvedit_uv_selected(scene, efa, tf, 1)) {
-                                       uvav = uv_average + efa->v2->tmp.l;
-                                       uvav->count++;
-                                       uvav->uv[0] += tf->uv[1][0];
-                                       uvav->uv[1] += tf->uv[1][1];
-                               }
+static int select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       ARegion *ar= CTX_wm_region(C);
+       float co[2];
+       int x, y;
 
-                               if(uvedit_uv_selected(scene, efa, tf, 2)) {
-                                       uvav = uv_average + efa->v3->tmp.l;
-                                       uvav->count++;
-                                       uvav->uv[0] += tf->uv[2][0];
-                                       uvav->uv[1] += tf->uv[2][1];
-                               }
+       x= event->x - ar->winrct.xmin;
+       y= event->y - ar->winrct.ymin;
 
-                               if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
-                                       uvav = uv_average + efa->v4->tmp.l;
-                                       uvav->count++;
-                                       uvav->uv[0] += tf->uv[3][0];
-                                       uvav->uv[1] += tf->uv[3][1];
-                               }
-                       }
-               }
-               
-               // apply uv welding
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+       UI_view2d_region_to_view(&ar->v2d, x, y, &co[0], &co[1]);
+       RNA_float_set_array(op->ptr, "location", co);
 
-                       if(uvedit_face_visible(scene, ima, efa, tf)) {
-                               if(uvedit_uv_selected(scene, efa, tf, 0)) {
-                                       uvav = uv_average + efa->v1->tmp.l;
-                                       tf->uv[0][0] = uvav->uv[0]/uvav->count;
-                                       tf->uv[0][1] = uvav->uv[1]/uvav->count;
-                               }
+       return select_loop_exec(C, op);
+}
 
-                               if(uvedit_uv_selected(scene, efa, tf, 1)) {
-                                       uvav = uv_average + efa->v2->tmp.l;
-                                       tf->uv[1][0] = uvav->uv[0]/uvav->count;
-                                       tf->uv[1][1] = uvav->uv[1]/uvav->count;
-                               }
+void UV_OT_select_loop(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Loop Select";
+       ot->idname= "UV_OT_select_loop";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* api callbacks */
+       ot->exec= select_loop_exec;
+       ot->invoke= select_loop_invoke;
+       ot->poll= ED_operator_uvedit;
 
-                               if(uvedit_uv_selected(scene, efa, tf, 2)) {
-                                       uvav = uv_average + efa->v3->tmp.l;
-                                       tf->uv[2][0] = uvav->uv[0]/uvav->count;
-                                       tf->uv[2][1] = uvav->uv[1]/uvav->count;
-                               }
+       /* properties */
+       RNA_def_boolean(ot->srna, "extend", 0,
+               "Extend", "Extend selection rather than clearing the existing selection.");
+       RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
+               "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds.", -100.0f, 100.0f);
+}
 
-                               if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
-                                       uvav = uv_average + efa->v4->tmp.l;
-                                       tf->uv[3][0] = uvav->uv[0]/uvav->count;
-                                       tf->uv[3][1] = uvav->uv[1]/uvav->count;
-                               }
-                       }
-               }
+/* ******************** linked select operator **************** */
 
-               MEM_freeN(uv_average);
+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= BKE_mesh_get_editmesh((Mesh*)obedit->data);
+       float limit[2];
+       int extend;
+
+       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;
        }
 
-       // XXX if(sima->flag & SI_BE_SQUARE)
-       // XXX  uvedit_constrain_square(scene, sima->image, em);
+       extend= RNA_boolean_get(op->ptr, "extend");
+       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); // XXX
+       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;
 }
 
-void UV_OT_stitch(wmOperatorType *ot)
+void UV_OT_select_linked(wmOperatorType *ot)
 {
        /* identifiers */
-       ot->name= "Stitch";
-       ot->idname= "UV_OT_stitch";
-       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       ot->name= "Select Linked";
+       ot->idname= "UV_OT_select_linked";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* api callbacks */
-       ot->exec= stitch_exec;
+       ot->exec= select_linked_exec;
        ot->poll= ED_operator_uvedit;
 
        /* 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_boolean(ot->srna, "extend", 0,
+               "Extend", "Extend selection rather than clearing the existing selection.");
 }
 
-/* ******************** (de)select all operator **************** */
+/* ******************** unlink selection operator **************** */
 
-static int select_inverse_exec(bContext *C, wmOperator *op)
+static int unlink_selection_exec(bContext *C, wmOperator *op)
 {
-       Scene *scene;
-       Object *obedit;
-       EditMesh *em;
+       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= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        EditFace *efa;
-       Image *ima;
        MTFace *tf;
-       
-       scene= CTX_data_scene(C);
-       obedit= CTX_data_edit_object(C);
-       em= ((Mesh*)obedit->data)->edit_mesh;
-       ima= CTX_data_edit_image(C);
 
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               // XXX selectswap_mesh();
+       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;
        }
-       else {
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+       
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 
-                       if(uvedit_face_visible(scene, ima, efa, tf)) {
-                               tf->flag ^= TF_SEL1;
-                               tf->flag ^= TF_SEL2;
-                               tf->flag ^= TF_SEL3;
-                               if(efa->v4) tf->flag ^= TF_SEL4;
+               if(uvedit_face_visible(scene, ima, efa, tf)) {
+                       if(efa->v4) {
+                               if(~tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4))
+                                       tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+                       }
+                       else {
+                               if(~tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
+                                       tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3);
                        }
                }
        }
+       
+       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
 
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
-
+       BKE_mesh_end_editmesh(obedit->data, em);
        return OPERATOR_FINISHED;
 }
 
-void UV_OT_select_inverse(wmOperatorType *ot)
+void UV_OT_unlink_selection(wmOperatorType *ot)
 {
        /* identifiers */
-       ot->name= "Select Invert";
-       ot->idname= "UV_OT_select_inverse";
-       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       ot->name= "Unlink Selection";
+       ot->idname= "UV_OT_unlink_selection";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
        /* api callbacks */
-       ot->exec= select_inverse_exec;
+       ot->exec= unlink_selection_exec;
        ot->poll= ED_operator_uvedit;
 }
 
-/* ******************** (de)select all operator **************** */
+/* ******************** border select operator **************** */
 
-static int de_select_all_exec(bContext *C, wmOperator *op)
+/* 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)
 {
-       Scene *scene;
-       Object *obedit;
-       EditMesh *em;
+       /* 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;
-       Image *ima;
        MTFace *tf;
-       int sel;
-       
-       scene= CTX_data_scene(C);
-       obedit= CTX_data_edit_object(C);
-       em= ((Mesh*)obedit->data)->edit_mesh;
-       ima= CTX_data_edit_image(C);
+       int nverts, i;
        
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               // XXX deselectall_mesh();
-       }
-       else {
-               sel= 0;
-
+       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;
+               
+               for(eve= em->verts.first; eve; eve= eve->next)
+                       eve->tmp.l = 0;
+               
                for(efa= em->faces.first; efa; efa= efa->next) {
-                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                       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;
+                       }
+               }
 
-                       if(uvedit_face_visible(scene, ima, efa, tf)) {
-                               if(tf->flag & (TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4)) {
-                                       sel= 1;
-                                       break;
+               /* 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) {
-                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+       }
+       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;
 
-                       if(uvedit_face_visible(scene, ima, efa, tf)) {
-                               if(efa->v4) {
-                                       if(sel) tf->flag &= ~(TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
-                                       else tf->flag |= (TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
-                               }
-                               else {
-                                       if(sel) tf->flag &= ~(TF_SEL1+TF_SEL2+TF_SEL3+TF_SEL4);
-                                       else tf->flag |= (TF_SEL1+TF_SEL2+TF_SEL3);
+                               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_vlist, tf_vlist, vlist_iter->tfindex);
+                                                       else
+                                                               uvedit_uv_deselect(scene, efa_vlist, tf_vlist, vlist_iter->tfindex);
+                                               }
+                                               vlist_iter = vlist_iter->next;
+                                       }
                                }
                        }
                }
+               EM_free_index_arrays();
+               EM_free_uv_vert_map(vmap);
+               
        }
-
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
-
-       return OPERATOR_FINISHED;
-}
-
-void UV_OT_de_select_all(wmOperatorType *ot)
-{
-       /* identifiers */
-       ot->name= "Select/Deselect All";
-       ot->idname= "UV_OT_de_select_all";
-       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
-       
-       /* api callbacks */
-       ot->exec= de_select_all_exec;
-       ot->poll= ED_operator_uvedit;
-}
-
-/* ******************** mouse select operator **************** */
-
-static int msel_hit(float *limit, unsigned int *hitarray, unsigned int vertexid, float **uv, float *uv2, int sticky)
-{
-       int i;
-       for(i=0; i< 4; i++) {
-               if(hitarray[i] == vertexid) {
-                       if(sticky == 2) {
-                               if(fabs(uv[i][0]-uv2[0]) < limit[0] &&
-                           fabs(uv[i][1]-uv2[1]) < limit[1])
-                                       return 1;
+       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);
                        }
-                       else return 1;
                }
        }
-       return 0;
+       BKE_mesh_end_editmesh(obedit->data, em);
 }
 
-static void find_nearest_uv_edge(Scene *scene, Image *ima, Object *obedit, MTFace **nearesttf, EditFace **nearestefa, int *nearestedge)
+static int border_select_exec(bContext *C, wmOperator *op)
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
-       MTFace *tf;
+       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;
-       float mvalf[2], v1[2], v2[2];
-       int i, nverts, mindist, dist, uval1[2], uval2[2];
-       short mval[2];
+       MTFace *tface;
+       rcti rect;
+       rctf rectf;
+       int change, pinned, select, faces;
 
-       mval[0]= mval[1]= 0; // XXX getmouseco_areawin(mval);
-       mvalf[0]= mval[0];
-       mvalf[1]= mval[1];
+       /* 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);
 
-       mindist= 0x7FFFFFF;
-       *nearesttf= NULL;
-       *nearestefa= NULL;
-       *nearestedge= 0;
+       /* figure out what to select/deselect */
+       select= (RNA_int_get(op->ptr, "event_type") == LEFTMOUSE); // XXX hardcoded
+       pinned= RNA_boolean_get(op->ptr, "pinned");
        
-       for(efa= em->faces.first; efa; efa= efa->next) {
-               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+       if(ts->uv_flag & UV_SYNC_SELECTION)
+               faces= (ts->selectmode == SCE_SELECT_FACE);
+       else
+               faces= (ts->uv_selectmode == UV_SELECT_FACE);
 
-               if(uvedit_face_visible(scene, ima, efa, tf)) {
-                       nverts= efa->v4? 4: 3;
-                       for(i=0; i<nverts; i++) {
-                               uval1[0]= uval1[1]= 0; // XXX uvco_to_areaco_noclip(tf->uv[i], uval1);
-                               uval2[0]= uval2[1]= 0; // XXX uvco_to_areaco_noclip(tf->uv[(i+1)%nverts], uval2);
+       /* do actual selection */
+       if(faces && !pinned) {
+               /* handle face selection mode */
+               float cent[2];
 
-                               v1[0]= uval1[0];
-                               v1[1]= uval1[1];
-                               v2[0]= uval2[0];
-                               v2[1]= uval2[1];
+               change= 0;
 
-                               dist= PdistVL2Dfl(mvalf, v1, v2);
-                               if(dist < mindist) {
-                                       *nearesttf= tf;
-                                       *nearestefa= efa;
-                                       *nearestedge= i;
-                                       mindist= dist;
+               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;
                                }
                        }
                }
-       }
-}
-
-static void find_nearest_tface(Scene *scene, Image *ima, Object *obedit, MTFace **nearesttf, EditFace **nearestefa)
-{
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
-       MTFace *tf;
-       EditFace *efa;
-       int i, nverts, mindist, dist, fcenter[2], uval[2];
-       short mval[2];
 
-       mval[0]= mval[1]= 0; // XXX getmouseco_areawin(mval);   
+               /* (de)selects all tagged faces and deals with sticky modes */
+               if(change)
+                       uv_faces_do_sticky(C, sima, scene, obedit, select);
+       }
+       else {
+               /* other selection modes */
+               change= 1;
 
-       mindist= 0x7FFFFFF;
-       *nearesttf= NULL;
-       *nearestefa= NULL;
-       
-       for(efa= em->faces.first; efa; efa= efa->next) {
-               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-               if(uvedit_face_visible(scene, ima, efa, tf)) {
-                       fcenter[0]= fcenter[1]= 0;
-                       nverts= efa->v4? 4: 3;
-                       for(i=0; i<nverts; i++) {
-                               uval[0]= uval[0]= 0; // XXX uvco_to_areaco_noclip(tf->uv[i], uval);
-                               fcenter[0] += uval[0];
-                               fcenter[1] += uval[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);
+                                       }
+                               }
                        }
+               }
+       }
 
-                       fcenter[0] /= nverts;
-                       fcenter[1] /= nverts;
-
-                       dist= abs(mval[0]- fcenter[0])+ abs(mval[1]- fcenter[1]);
-                       if(dist < mindist) {
-                               *nearesttf= tf;
-                               *nearestefa= efa;
-                               mindist= dist;
+       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;
+} 
 
-static int nearest_uv_between(MTFace *tf, int nverts, int id, short *mval, int *uval)
+void UV_OT_select_border(wmOperatorType *ot)
 {
-       float m[3], v1[3], v2[3], c1, c2;
-       int id1, id2;
-
-       id1= (id+nverts-1)%nverts;
-       id2= (id+nverts+1)%nverts;
+       /* 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.");
 
-       m[0] = (float)(mval[0]-uval[0]);
-       m[1] = (float)(mval[1]-uval[1]);
-       Vec2Subf(v1, tf->uv[id1], tf->uv[id]);
-       Vec2Subf(v2, tf->uv[id2], tf->uv[id]);
+       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);
+}
 
-       /* m and v2 on same side of v-v1? */
-       c1= v1[0]*m[1] - v1[1]*m[0];
-       c2= v1[0]*v2[1] - v1[1]*v2[0];
+/* ******************** circle select operator **************** */
 
-       if(c1*c2 < 0.0f)
-               return 0;
+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];
 
-       /* m and v1 on same side of v-v2? */
-       c1= v2[0]*m[1] - v2[1]*m[0];
-       c2= v2[0]*v1[1] - v2[1]*v1[0];
+       x= (uv[0] - offset[0])*ell[0];
+       y= (uv[1] - offset[1])*ell[1];
 
-       return (c1*c2 >= 0.0f);
+       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);
+       }
 }
 
-void find_nearest_uv(Scene *scene, Image *ima, Object *obedit, MTFace **nearesttf, EditFace **nearestefa, unsigned int *nearestv, int *nearestuv)
+int circle_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);
+       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 *tf;
-       int i, nverts, mindist, dist, uval[2];
-       short mval[2];
+       MTFace *tface;
+       int x, y, radius, width, height, select;
+       float zoomx, zoomy, offset[2], ellipse[2];
 
-       mval[0]= mval[1]= 0; // XXX getmouseco_areawin(mval);   
+       /* 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");
 
-       mindist= 0x7FFFFFF;
-       if(nearesttf) *nearesttf= NULL;
-       if(nearestefa) *nearestefa= NULL;
-       
-       if(nearestv) {
-               EditVert *ev;
-               for(i=0, ev=em->verts.first; ev; ev = ev->next, i++)
-                       ev->tmp.l = i;
-       }
+       /* 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) {
-               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-               if(uvedit_face_visible(scene, ima, efa, tf)) {
-                       nverts= efa->v4? 4: 3;
-                       for(i=0; i<nverts; i++) {
-                               uval[0]= uval[1]= 0; // XXX uvco_to_areaco_noclip(tf->uv[i], uval);
-                               dist= abs(mval[0]-uval[0]) + abs(mval[1]-uval[1]);
+               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(uvedit_uv_selected(scene, efa, tf, i))
-                                       dist += 5;
+       if(select) EM_select_flush(em);
+       else EM_deselect_flush(em);
 
-                               if(dist<=mindist) {
-                                       if(dist==mindist)
-                                               if(!nearest_uv_between(tf, nverts, i, mval, uval))
-                                                       continue;
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
 
-                                       mindist= dist;
-                                       *nearestuv= i;
-                                       
-                                       if(nearesttf)           *nearesttf= tf;
-                                       if(nearestefa)          *nearestefa= efa;
-                                       if(nearestv) {
-                                               if(i==0) *nearestv=  efa->v1->tmp.l;
-                                               else if(i==1) *nearestv=  efa->v2->tmp.l;
-                                               else if(i==2) *nearestv=  efa->v3->tmp.l;
-                                               else *nearestv=  efa->v4->tmp.l;
-                                       }
-                               }
-                       }
-               }
-       }
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;
 }
 
-void mouse_select_sima(bContext *C, SpaceImage *sima, Scene *scene, Image *ima, Object *obedit)
+void UV_OT_circle_select(wmOperatorType *ot)
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
-       EditFace *efa;
-       MTFace *tf, *nearesttf;
-       EditFace *nearestefa=NULL;
-       int a, selectsticky, edgeloop, actface, nearestuv, nearestedge, i, shift, island=0;
-       char sticky= 0;
-       int flush = 0; /* 0 == dont flush, 1 == sel, -1 == desel;  only use when selection sync is enabled */
-       unsigned int hitv[4], nearestv;
-       float *hituv[4], limit[2];
+       /* identifiers */
+       ot->name= "Circle Select";
+       ot->idname= "UV_OT_circle_select";
        
-       if(!uvedit_test(obedit)) return;
-
-       uvedit_connection_limit(C, limit, 0.05);
+       /* api callbacks */
+       ot->invoke= WM_gesture_circle_invoke;
+       ot->modal= WM_gesture_circle_modal;
+       ot->exec= circle_select_exec;
+       ot->poll= ED_operator_uvedit;
        
-       edgeloop= 0; // XXX G.qual & LR_ALTKEY;
-       shift= 0; // XXX G.qual & LR_SHIFTKEY;
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               /* copy from mesh */
-               if(scene->selectmode == SCE_SELECT_FACE) {
-                       actface= 1;
-                       sticky= 0;
-               }
-               else {
-                       actface= scene->selectmode & SCE_SELECT_FACE;
-                       sticky= 2;
-               }
-       }
-       else {
-               /* normal operation */
-               actface= scene->toolsettings->uv_selectmode == UV_SELECT_FACE;
-               island= scene->toolsettings->uv_selectmode == UV_SELECT_ISLAND;
-               
-               switch(sima->sticky) {
-               case SI_STICKY_LOC:
-                       sticky=2;
-                       break;
-               case SI_STICKY_DISABLE:
-                       sticky=0;
-                       break;
-               case SI_STICKY_VERTEX:
-                       if(0) // XXX G.qual & LR_CTRLKEY)
-                               sticky=0;
-                       else
-                               sticky=1;
-                       break;
-               }
-       }
+       /* 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);
+}
 
-       if(edgeloop) {
-               find_nearest_uv_edge(scene, ima, obedit, &nearesttf, &nearestefa, &nearestedge);
-               if(nearesttf==NULL)
-                       return;
+/* ******************** snap cursor operator **************** */
 
-               select_edgeloop_tface_uv(C, scene, ima, obedit, nearestefa, nearestedge, shift, &flush);
-       }
-       else if(actface) {
-               find_nearest_tface(scene, ima, obedit, &nearesttf, &nearestefa);
-               if(nearesttf==NULL)
-                       return;
-               
-               EM_set_actFace(em, nearestefa);
+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;
+}
 
-               for(i=0; i<4; i++)
-                       hituv[i]= nearesttf->uv[i];
+static void snap_cursor_to_pixels(SpaceImage *sima, View2D *v2d)
+{
+       int width= 0, height= 0;
 
-               hitv[0]= nearestefa->v1->tmp.l;
-               hitv[1]= nearestefa->v2->tmp.l;
-               hitv[2]= nearestefa->v3->tmp.l;
-               
-               if(nearestefa->v4)      hitv[3]= nearestefa->v4->tmp.l;
-               else                            hitv[3]= 0xFFFFFFFF;
-       }
-       else if(island) {
+       ED_space_image_size(sima, &width, &height);
+       snap_uv_to_pixel(v2d->cursor, width, height);
+}
 
-       }
-       else {
-               find_nearest_uv(scene, ima, obedit, &nearesttf, &nearestefa, &nearestv, &nearestuv);
-               if(nearesttf==NULL)
-                       return;
+static int snap_cursor_to_selection(Scene *scene, Image *ima, Object *obedit, View2D *v2d)
+{
+       return uvedit_center(scene, ima, obedit, v2d->cursor, 0);
+}
 
-               if(sticky) {
-                       for(i=0; i<4; i++)
-                               hitv[i]= 0xFFFFFFFF;
-                       hitv[nearestuv]= nearestv;
-                       hituv[nearestuv]= nearesttf->uv[nearestuv];
-               }
-       }
+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;
 
-       if(island) {
-               if(shift) select_linked_tface_uv(C, scene, ima, obedit, 1);
-               else select_linked_tface_uv(C, scene, ima, obedit, 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;
        }
-       else if(!edgeloop && shift) {
-               /* (de)select face */
-               if(actface) {
-                       if(uvedit_face_selected(scene, nearestefa, nearesttf)) {
-                               uvedit_face_deselect(scene, nearestefa, nearesttf);
-                               selectsticky= 0;
-                       }
-                       else {
-                               uvedit_face_select(scene, nearestefa, nearesttf);
-                               selectsticky= 1;
-                       }
-                       flush = -1;
-               }
-               /* (de)select uv node */
-               else {
-                       if(uvedit_uv_selected(scene, nearestefa, nearesttf, nearestuv)) {
-                               uvedit_uv_deselect(scene, nearestefa, nearesttf, nearestuv);
-                               selectsticky= 0;
-                       }
-                       else {
-                               uvedit_uv_select(scene, nearestefa, nearesttf, nearestuv);
-                               selectsticky= 1;
-                       }
-                       flush = 1;
-               }
 
-               /* (de)select sticky uv nodes */
-               if(sticky || actface) {
-                       EditVert *ev;
-                       
-                       for(a=0, ev=em->verts.first; ev; ev = ev->next, a++)
-                               ev->tmp.l = a;
-                       
-                       /* deselect */
-                       if(selectsticky==0) {
-                               for(efa= em->faces.first; efa; efa= efa->next) {
-                                       tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                                       if(uvedit_face_visible(scene, ima, efa, tf)) {
-                                               /*if(nearesttf && tf!=nearesttf) tf->flag &=~ TF_ACTIVE;*/ /* TODO - deal with editmesh active face */
-                                               if(!sticky) continue;
+       if(!change)
+               return OPERATOR_CANCELLED;
        
-                                               if(msel_hit(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
-                                                       uvedit_uv_deselect(scene, efa, tf, 0);
-                                               if(msel_hit(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
-                                                       uvedit_uv_deselect(scene, efa, tf, 1);
-                                               if(msel_hit(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
-                                                       uvedit_uv_deselect(scene, efa, tf, 2);
-                                               if(efa->v4)
-                                                       if(msel_hit(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
-                                                               uvedit_uv_deselect(scene, efa, tf, 3);
-                                       }
-                               }
-                               flush = -1;
-                       }
-                       /* select */
-                       else {
-                               for(efa= em->faces.first; efa; efa= efa->next) {
-                                       tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                                       if(uvedit_face_visible(scene, ima, efa, tf)) {
-                                               if(!sticky) continue;
-                                               if(msel_hit(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
-                                                       uvedit_uv_select(scene, efa, tf, 0);
-                                               if(msel_hit(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
-                                                       uvedit_uv_select(scene, efa, tf, 1);
-                                               if(msel_hit(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
-                                                       uvedit_uv_select(scene, efa, tf, 2);
-                                               if(efa->v4)
-                                                       if(msel_hit(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
-                                                               uvedit_uv_select(scene, efa, tf, 3);
-                                       }
-                               }
-                               
-                               if(actface)
-                                       EM_set_actFace(em, nearestefa);
-                               
-                               flush = 1;
-                       }                       
-               }
-       }
-       else if(!edgeloop) {
-               /* select face and deselect other faces */ 
-               if(actface) {
-                       for(efa= em->faces.first; efa; efa= efa->next) {
-                               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                               uvedit_face_deselect(scene, efa, tf);
-                       }
-                       if(nearesttf) {
-                               uvedit_face_select(scene, nearestefa, nearesttf);
-                               EM_set_actFace(em, nearestefa);
-                       }
-                               
-               }
+       ED_region_tag_redraw(ar);
 
-               /* deselect uvs, and select sticky uvs */
-               for(efa= em->faces.first; efa; efa= efa->next) {
-                       tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                       if(uvedit_face_visible(scene, ima, efa, tf)) {
-                               if(!actface) uvedit_face_deselect(scene, efa, tf);
-                               if(!sticky) continue;
-
-                               if(msel_hit(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
-                                       uvedit_uv_select(scene, efa, tf, 0);
-                               if(msel_hit(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
-                                       uvedit_uv_select(scene, efa, tf, 1);
-                               if(msel_hit(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
-                                       uvedit_uv_select(scene, efa, tf, 2);
-                               if(efa->v4)
-                                       if(msel_hit(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
-                                               uvedit_uv_select(scene, efa, tf, 3);
-                               flush= 1;
-                       }
-               }
-               
-               if(!actface) {
-                       uvedit_uv_select(scene, nearestefa, nearesttf, nearestuv);
-                       flush= 1;
-               }
-       }
-       
-       // XXX force_draw(1);
-       
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               /* flush for mesh selection */
-               if(scene->selectmode != SCE_SELECT_FACE) {
-                       if(flush==1)            EM_select_flush(em);
-                       else if(flush==-1)      EM_deselect_flush(em);
-               }
-               // XXX allqueue(REDRAWVIEW3D, 0); /* mesh selection has changed */
-       }
-       
-       // XXX BIF_undo_push("Select UV");
-       // XXX rightmouse_transform();
+       return OPERATOR_FINISHED;
 }
 
-void borderselect_sima(bContext *C, SpaceImage *sima, Scene *scene, Image *ima, Object *obedit, short whichuvs)
+void UV_OT_snap_cursor(wmOperatorType *ot)
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
-       EditFace *efa;
-       MTFace *tface;
-       rcti rect;
-       rctf rectf;
-       int val, ok = 1;
-       short mval[2], select;
+       static EnumPropertyItem target_items[] = {
+               {0, "PIXELS", 0, "Pixels", ""},
+               {1, "SELECTION", 0, "Selection", ""},
+               {0, NULL, 0, NULL, NULL}};
 
-       if(!uvedit_test(obedit)) return;
-
-       val= 0; // XXX get_border(&rect, 3);
-       select = 0; // XXX (val==LEFTMOUSE) ? 1 : 0; 
+       /* identifiers */
+       ot->name= "Snap Cursor";
+       ot->idname= "UV_OT_snap_cursor";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
-       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(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;
-                                       }
-                               }
-                       }
-                       /* (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])) {
-                                                       
-                                                       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(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);
-                               }
-                       }
-                       // XXX allqueue(REDRAWVIEW3D, 0); /* mesh selection has changed */
-                       
-                       // XXX BIF_undo_push("Border select UV");
-                       // XXX scrarea_queue_winredraw(curarea);
-               }
-       }
+       /* 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.");
 }
 
-int snap_uv_sel_to_curs(Scene *scene, Image *ima, Object *obedit, View2D *v2d)
+/* ******************** snap selection operator **************** */
+
+static int snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, View2D *v2d)
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        EditFace *efa;
        MTFace *tface;
-       short change = 0;
+       short change= 0;
 
        for(efa= em->faces.first; efa; efa= efa->next) {
                tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
@@ -1469,15 +2337,18 @@ int snap_uv_sel_to_curs(Scene *scene, Image *ima, Object *obedit, View2D *v2d)
                        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;
+
+                       change= 1;
                }
        }
+
+       BKE_mesh_end_editmesh(obedit->data, em);
        return change;
 }
 
-int snap_uv_sel_to_adj_unsel(Scene *scene, Image *ima, Object *obedit)
+static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit)
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        EditFace *efa;
        EditVert *eve;
        MTFace *tface;
@@ -1494,12 +2365,14 @@ int snap_uv_sel_to_adj_unsel(Scene *scene, Image *ima, Object *obedit)
         * 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 */
@@ -1514,10 +2387,7 @@ int snap_uv_sel_to_adj_unsel(Scene *scene, Image *ima, Object *obedit)
        
        /* 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)) {
-                       
                        /* 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];
@@ -1531,592 +2401,190 @@ int snap_uv_sel_to_adj_unsel(Scene *scene, Image *ima, Object *obedit)
                                usercount[efa->v2->tmp.l]++;
                                change = 1;
                        }
-                       if(efa->v3->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 2))) {
-                               coords[efa->v3->tmp.l*2] +=             tface->uv[2][0];
-                               coords[(efa->v3->tmp.l*2)+1] += tface->uv[2][1];
-                               usercount[efa->v3->tmp.l]++;
-                               change = 1;
-                       }
-                       
-                       if(efa->v4) {
-                               if(efa->v4->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 3))) {
-                                       coords[efa->v4->tmp.l*2] +=             tface->uv[3][0];
-                                       coords[(efa->v4->tmp.l*2)+1] += tface->uv[3][1];
-                                       usercount[efa->v4->tmp.l]++;
-                                       change = 1;
-                               }
-                       }
-               }
-       }
-       
-       /* no other verts selected, bail out */
-       if(!change) {
-               MEM_freeN(coords);
-               MEM_freeN(usercount);
-               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) &&
-                                       efa->v1->tmp.l >= 0 &&
-                                       (users = usercount[efa->v1->tmp.l])
-                       ) {
-                               tface->uv[0][0] = coords[efa->v1->tmp.l*2]              / users;
-                               tface->uv[0][1] = coords[(efa->v1->tmp.l*2)+1]  / users;
-                       }
-
-                       if(     uvedit_uv_selected(scene, efa, tface, 1) &&
-                                       efa->v2->tmp.l >= 0 &&
-                                       (users = usercount[efa->v2->tmp.l])
-                       ) {
-                               tface->uv[1][0] = coords[efa->v2->tmp.l*2]              / users;
-                               tface->uv[1][1] = coords[(efa->v2->tmp.l*2)+1]  / users;
-                       }
-                       
-                       if(     uvedit_uv_selected(scene, efa, tface, 2) &&
-                                       efa->v3->tmp.l >= 0 &&
-                                       (users = usercount[efa->v3->tmp.l])
-                       ) {
-                               tface->uv[2][0] = coords[efa->v3->tmp.l*2]              / users;
-                               tface->uv[2][1] = coords[(efa->v3->tmp.l*2)+1]  / users;
-                       }
-                       
-                       if(efa->v4) {
-                               if(     uvedit_uv_selected(scene, efa, tface, 3) &&
-                                               efa->v4->tmp.l >= 0 &&
-                                               (users = usercount[efa->v4->tmp.l])
-                               ) {
-                                       tface->uv[3][0] = coords[efa->v4->tmp.l*2]              / users;
-                                       tface->uv[3][1] = coords[(efa->v4->tmp.l*2)+1]  / users;
-                               }
-                       }
-               }
-       }
-       
-       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;  
-}
-
-int snap_uv_sel_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit) /* warning, sanity checks must alredy be done */
-{
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
-       Image *ima= sima->image;
-       EditFace *efa;
-       MTFace *tface;
-       int width= 0, height= 0;
-       float w, h;
-       short change = 0;
-
-       // XXX get_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(efa->v4)
-                               if(uvedit_uv_selected(scene, efa, tface, 3)) snap_coord_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(!uvedit_test(obedit)) return 0;
-       return uvedit_center(scene, ima, obedit, v2d->cursor, 0);
-}
-
-void snap_menu_sima(SpaceImage *sima, Scene *scene, Object *obedit, View2D *v2d)
-{
-       short event;
-
-       if(!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) {
-               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;
-               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);
-       }
-}
-
-// see below:
-/** gets image dimensions of the 2D view 'v' */
-static void getSpaceImageDimension(SpaceImage *sima, ARegion *ar, float *xy)
-{
-       float zoomx= 0, zoomy= 0;
-       int width= 0, height= 0;
-
-       // XXX get_space_image_size(sima, &width, &height);
-       // XXX get_space_image_zoom(sima, ar, &zoomx, &zoomy);
-
-       xy[0]= width*zoomx;
-       xy[1]= height*zoomy;
-}
-
-/** Callback function called by circle_selectCB to enable 
-  * brush select in UV editor.
-  */
-
-void uvedit_selectionCB(SpaceImage *sima, Scene *scene, ARegion *ar, short selecting, Object *obedit, short *mval, float rad) 
-{
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
-       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]);
-       
-       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);
-               }
-
-               /* 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);
-               }
-#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);
-       }
-}
-
-void select_linked_tface_uv(bContext *C, Scene *scene, Image *ima, Object *obedit, int mode) /* TODO */
-{
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
-       EditFace *efa, *nearestefa=NULL;
-       MTFace *tf, *nearesttf=NULL;
-       UvVertMap *vmap;
-       UvMapVert *vlist, *iterv, *startv;
-       unsigned int *stack, stacksize= 0, nearestv;
-       char *flag;
-       int a, nearestuv, i, nverts, j;
-       float limit[2];
-
-       if(!uvedit_test(obedit)) return;
-
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               // XXX error("Can't select linked when Sync Mesh Selection is enabled");
-               return;
-       }
-       
-       if(mode == 2) {
-               nearesttf= NULL;
-               nearestuv= 0;
-       }
-       if(mode!=2) {
-               find_nearest_uv(scene, ima, obedit, &nearesttf, &nearestefa, &nearestv, &nearestuv);
-               if(nearesttf==NULL)
-                       return;
-       }
-
-       uvedit_connection_limit(C, limit, 0.05);
-       vmap= EM_make_uv_vert_map(em, 1, 1, limit);
-       if(vmap == NULL)
-               return;
-
-       stack= MEM_mallocN(sizeof(*stack)* BLI_countlist(&em->faces), "UvLinkStack");
-       flag= MEM_callocN(sizeof(*flag)*BLI_countlist(&em->faces), "UvLinkFlag");
-
-       if(mode == 2) {
-               for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
-                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                       if(uvedit_face_visible(scene, ima, efa, tf)) {
-                               if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) {
-                                       stack[stacksize]= a;
-                                       stacksize++;
-                                       flag[a]= 1;
-                               }
-                       }
-               }
-       }
-       else {
-               for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
-                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                       if(tf == nearesttf) {
-                               stack[stacksize]= a;
-                               stacksize++;
-                               flag[a]= 1;
-                               break;
-                       }
-               }
-       }
-
-       while(stacksize > 0) {
-               stacksize--;
-               a= stack[stacksize];
-               
-               for(j=0, efa= em->faces.first; efa; efa= efa->next, j++) {
-                       if(j==a) {
-                               tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                               break;
-                       }
-               }
-
-               nverts= efa->v4? 4: 3;
-
-               for(i=0; i<nverts; i++) {
-                       /* make_uv_vert_map_EM sets verts tmp.l to the indicies */
-                       vlist= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l);
-                       
-                       startv= vlist;
-
-                       for(iterv=vlist; iterv; iterv=iterv->next) {
-                               if(iterv->separate)
-                                       startv= iterv;
-                               if(iterv->f == a)
-                                       break;
-                       }
-
-                       for(iterv=startv; iterv; iterv=iterv->next) {
-                               if((startv != iterv) && (iterv->separate))
-                                       break;
-                               else if(!flag[iterv->f]) {
-                                       flag[iterv->f]= 1;
-                                       stack[stacksize]= iterv->f;;
-                                       stacksize++;
+                       if(efa->v3->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 2))) {
+                               coords[efa->v3->tmp.l*2] +=             tface->uv[2][0];
+                               coords[(efa->v3->tmp.l*2)+1] += tface->uv[2][1];
+                               usercount[efa->v3->tmp.l]++;
+                               change = 1;
+                       }
+                       
+                       if(efa->v4) {
+                               if(efa->v4->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 3))) {
+                                       coords[efa->v4->tmp.l*2] +=             tface->uv[3][0];
+                                       coords[(efa->v4->tmp.l*2)+1] += tface->uv[3][1];
+                                       usercount[efa->v4->tmp.l]++;
+                                       change = 1;
                                }
                        }
                }
        }
-
-       if(mode==0 || mode==2) {
-               for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
-                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                       if(flag[a])
-                               tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
-                       else
-                               tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
-               }
+       
+       /* no other verts selected, bail out */
+       if(!change) {
+               MEM_freeN(coords);
+               MEM_freeN(usercount);
+               BKE_mesh_end_editmesh(obedit->data, em);
+               return change;
        }
-       else if(mode==1) {
-               for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
-                       if(flag[a]) {
-                               tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                               if(efa->v4) {
-                                       if((tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)))
-                                               break;
-                               }
-                               else if(tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
-                                       break;
+       
+       /* copy the averaged unselected UVs back to the selected UVs */
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               if((tface=(MTFace *)efa->tmp.p)) {
+                       
+                       if(     uvedit_uv_selected(scene, efa, tface, 0) &&
+                                       efa->v1->tmp.l >= 0 &&
+                                       (users = usercount[efa->v1->tmp.l])
+                       ) {
+                               tface->uv[0][0] = coords[efa->v1->tmp.l*2]              / users;
+                               tface->uv[0][1] = coords[(efa->v1->tmp.l*2)+1]  / users;
                        }
-               }
 
-               if(efa) {
-                       for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
-                               if(flag[a]) {
-                                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                                       tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
-                               }
+                       if(     uvedit_uv_selected(scene, efa, tface, 1) &&
+                                       efa->v2->tmp.l >= 0 &&
+                                       (users = usercount[efa->v2->tmp.l])
+                       ) {
+                               tface->uv[1][0] = coords[efa->v2->tmp.l*2]              / users;
+                               tface->uv[1][1] = coords[(efa->v2->tmp.l*2)+1]  / users;
                        }
-               }
-               else {
-                       for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
-                               if(flag[a]) {
-                                       tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                                       tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
+                       
+                       if(     uvedit_uv_selected(scene, efa, tface, 2) &&
+                                       efa->v3->tmp.l >= 0 &&
+                                       (users = usercount[efa->v3->tmp.l])
+                       ) {
+                               tface->uv[2][0] = coords[efa->v3->tmp.l*2]              / users;
+                               tface->uv[2][1] = coords[(efa->v3->tmp.l*2)+1]  / users;
+                       }
+                       
+                       if(efa->v4) {
+                               if(     uvedit_uv_selected(scene, efa, tface, 3) &&
+                                               efa->v4->tmp.l >= 0 &&
+                                               (users = usercount[efa->v4->tmp.l])
+                               ) {
+                                       tface->uv[3][0] = coords[efa->v4->tmp.l*2]              / users;
+                                       tface->uv[3][1] = coords[(efa->v4->tmp.l*2)+1]  / users;
                                }
                        }
                }
        }
        
-       MEM_freeN(stack);
-       MEM_freeN(flag);
-       EM_free_uv_vert_map(vmap);
+       MEM_freeN(coords);
+       MEM_freeN(usercount);
 
-       // XXX BIF_undo_push("Select linked UV");
-       // XXX scrarea_queue_winredraw(curarea);
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return change;
 }
 
-void unlink_selection(Scene *scene, Image *ima, Object *obedit)
+static int snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       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;
 
-       if(!uvedit_test(obedit)) return;
-
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               ; // XXX error("Can't select unlinked when Sync Mesh Selection is enabled");
-               return;
-       }
+       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);
+               tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
                if(uvedit_face_visible(scene, ima, efa, tface)) {
-                       if(efa->v4) {
-                               if(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4))
-                                       tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
-                       }
-                       else {
-                               if(~tface->flag & (TF_SEL1|TF_SEL2|TF_SEL3))
-                                       tface->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3);
-                       }
+                       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_uv_to_pixel(tface->uv[3], w, h);
+
+                       change = 1;
                }
        }
-       
-       // XXX BIF_undo_push("Unlink UV selection");
-       // XXX scrarea_queue_winredraw(curarea);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return change;
 }
 
-/* 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)
+static int snap_selection_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:
+                       change= snap_uvs_to_pixels(sima, scene, obedit);
+                       break;
+               case 1:
+                       change= snap_uvs_to_cursor(scene, ima, obedit, &ar->v2d);
+                       break;
+               case 2:
+                       change= snap_uvs_to_adjacent_unselected(scene, ima, obedit);
+                       break;
+       }
+
+       if(!change)
+               return OPERATOR_CANCELLED;
        
-       /* 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;
-       EditFace *efa;
-       MTFace *tf;
-       int nverts, i;
-       
-       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);
-                               }
-                       }
-               }
-       } 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_connection_limit(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;
+       DAG_id_flush_update(obedit->data, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, 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;
+       return OPERATOR_FINISHED;
+}
 
-                                               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_vlist, tf_vlist, vlist_iter->tfindex);
-                                                       else
-                                                               uvedit_uv_deselect(scene, efa_vlist, tf_vlist, vlist_iter->tfindex);
-                                               }
-                                               vlist_iter = vlist_iter->next;
-                                       }
-                               }
-                       }
-               }
-               EM_free_index_arrays();
-               EM_free_uv_vert_map(vmap);
-               
-       }
-       else { /* SI_STICKY_DISABLE or scene->toolsettings->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);
-                       }
-               }
-       }
+void UV_OT_snap_selection(wmOperatorType *ot)
+{
+       static EnumPropertyItem target_items[] = {
+               {0, "PIXELS", 0, "Pixels", ""},
+               {1, "CURSOR", 0, "Cursor", ""},
+               {2, "ADJACENT_UNSELECTED", 0, "Adjacent Unselected", ""},
+               {0, NULL, 0, NULL, NULL}};
+
+       /* 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;
+
+       /* properties */
+       RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UV's to.");
 }
 
-void pin_tface_uv(Scene *scene, Image *ima, Object *obedit, int mode)
+/* ******************** pin operator **************** */
+
+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;
        MTFace *tface;
-       
-       if(!uvedit_test(obedit)) return;
+       int clear= RNA_boolean_get(op->ptr, "clear");
        
        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(!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(mode ==0) {
+                       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;
@@ -2126,20 +2594,41 @@ void pin_tface_uv(Scene *scene, Image *ima, Object *obedit, int mode)
                }
        }
        
-       // XXX BIF_undo_push("Pin UV");
-       // XXX scrarea_queue_winredraw(curarea);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;
+}
+
+void UV_OT_pin(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Pin";
+       ot->idname= "UV_OT_pin";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* 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.");
 }
 
-void select_pinned_tface_uv(Scene *scene, Image *ima, Object *obedit)
+/******************* select pinned operator ***************/
+
+static int select_pinned_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;
        MTFace *tface;
        
-       if(!uvedit_test(obedit)) return;
-       
        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);
@@ -2147,240 +2636,499 @@ void select_pinned_tface_uv(Scene *scene, Image *ima, Object *obedit)
                        if(efa->v4) {
                                if(tface->unwrap & TF_PIN4) uvedit_uv_select(scene, efa, tface, 3);
                        }
-                       
                }
        }
        
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               // XXX allqueue(REDRAWVIEW3D, 0); /* mesh selection has changed */
-       }
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;
+}
+
+void UV_OT_select_pinned(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Selected Pinned";
+       ot->idname= "UV_OT_select_pinned";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
-       // XXX BIF_undo_push("Select Pinned UVs");
-       // XXX scrarea_queue_winredraw(curarea);
+       /* api callbacks */
+       ot->exec= select_pinned_exec;
+       ot->poll= ED_operator_uvedit;
 }
 
-/* UV edge loop select, follows same rules as editmesh */
+/********************** hide operator *********************/
 
-static void uv_vertex_loop_flag(UvMapVert *first)
+static int hide_exec(bContext *C, wmOperator *op)
 {
-       UvMapVert *iterv;
-       int count= 0;
+       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;
 
-       for(iterv=first; iterv; iterv=iterv->next) {
-               if(iterv->separate && iterv!=first)
-                       break;
+       if(ts->uv_flag & UV_SYNC_SELECTION) {
+               EM_hide_mesh(em, swap);
+               WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
 
-               count++;
+               BKE_mesh_end_editmesh(obedit->data, em);
+               return OPERATOR_FINISHED;
        }
        
-       if(count < 5)
-               first->flag= 1;
+       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(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))==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);
+                               }
+                       }
+               }
+       }
+       else {
+               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) {
+                                       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;
 }
 
-static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, EditFace *efa, int a)
+void UV_OT_hide(wmOperatorType *ot)
 {
-       UvMapVert *iterv, *first;
+       /* identifiers */
+       ot->name= "Hide Selected";
+       ot->idname= "UV_OT_hide";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
-       first= EM_get_uv_map_vert(vmap, (*(&efa->v1 + a))->tmp.l);
+       /* api callbacks */
+       ot->exec= hide_exec;
+       ot->poll= ED_operator_uvedit;
 
-       for(iterv=first; iterv; iterv=iterv->next) {
-               if(iterv->separate)
-                       first= iterv;
-               if(iterv->f == efa->tmp.l)
-                       return first;
-       }
-       
-       return NULL;
+       /* props */
+       RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
 }
 
-static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface)
+/****************** reveal operator ******************/
+
+static int reveal_exec(bContext *C, wmOperator *op)
 {
-       UvMapVert *iterv1, *iterv2;
+       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;
-       int tot = 0;
+       MTFace *tf;
+       int facemode= sima ? sima->flag & SI_SELACTFACE : 0;
+       int stickymode= sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
+       
+       /* 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);
 
-       /* count number of faces this edge has */
-       for(iterv1=first1; iterv1; iterv1=iterv1->next) {
-               if(iterv1->separate && iterv1 != first1)
-                       break;
+               BKE_mesh_end_editmesh(obedit->data, em);
+               return OPERATOR_FINISHED;
+       }
+       
+       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 {
+                       /* 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);
 
-               for(iterv2=first2; iterv2; iterv2=iterv2->next) {
-                       if(iterv2->separate && iterv2 != first2)
-                               break;
+                                               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;}
 
-                       if(iterv1->f == iterv2->f) {
-                               /* if face already tagged, don't do this edge */
-                               efa= EM_get_face_for_index(iterv1->f);
-                               if(efa->f1)
-                                       return 0;
+                                               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);
 
-                               tot++;
-                               break;
+                       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(*totface == 0) /* start edge */
-               *totface= tot;
-       else if(tot != *totface) /* check for same number of faces as start edge */
-               return 0;
-
-       /* tag the faces */
-       for(iterv1=first1; iterv1; iterv1=iterv1->next) {
-               if(iterv1->separate && iterv1 != first1)
-                       break;
-
-               for(iterv2=first2; iterv2; iterv2=iterv2->next) {
-                       if(iterv2->separate && iterv2 != first2)
-                               break;
+                               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;}
 
-                       if(iterv1->f == iterv2->f) {
-                               efa= EM_get_face_for_index(iterv1->f);
-                               efa->f1= 1;
-                               break;
+                               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);
        }
 
-       return 1;
+       WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
+
+       BKE_mesh_end_editmesh(obedit->data, em);
+       return OPERATOR_FINISHED;
 }
 
-void select_edgeloop_tface_uv(bContext *C, Scene *scene, Image *ima, Object *obedit, EditFace *startefa, int starta, int shift, int *flush)
+void UV_OT_reveal(wmOperatorType *ot)
 {
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
-       EditVert *eve;
-       EditFace *efa;
-       MTFace *tface;
-       UvVertMap *vmap;
-       UvMapVert *iterv1, *iterv2;
-       float limit[2];
-       int a, count, looking, nverts, starttotface, select;
+       /* identifiers */
+       ot->name= "Reveal Hidden";
+       ot->idname= "UV_OT_reveal";
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
        
-       if(!uvedit_test(obedit)) return;
+       /* api callbacks */
+       ot->exec= reveal_exec;
+       ot->poll= ED_operator_uvedit;
+}
 
-       /* setup */
-       EM_init_index_arrays(em, 0, 0, 1);
+/******************** set 3d cursor operator ********************/
 
-       uvedit_connection_limit(C, limit, 0.05);
-       vmap= EM_make_uv_vert_map(em, 0, 0, limit);
+static int set_2d_cursor_exec(bContext *C, wmOperator *op)
+{
+       ARegion *ar= CTX_wm_region(C);
+       float location[2];
 
-       for(count=0, eve=em->verts.first; eve; count++, eve= eve->next)
-               eve->tmp.l = count;
+       RNA_float_get_array(op->ptr, "location", location);
+       ar->v2d.cursor[0]= location[0];
+       ar->v2d.cursor[1]= location[1];
+       
+       ED_area_tag_redraw(CTX_wm_area(C));
+       
+       return OPERATOR_FINISHED;
+}
 
-       for(count=0, efa= em->faces.first; efa; count++, efa= efa->next) {
-               if(!shift) {
-                       tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                       uvedit_face_deselect(scene, efa, tface);
-               }
+static int set_2d_cursor_invoke(bContext *C, wmOperator *op, wmEvent *event)
+{
+       ARegion *ar= CTX_wm_region(C);
+       int x, y;
+       float location[2];
 
-               efa->tmp.l= count;
-               efa->f1= 0;
-       }
+       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";
        
-       /* set flags for first face and verts */
-       nverts= (startefa->v4)? 4: 3;
-       iterv1= uv_vertex_map_get(vmap, startefa, starta);
-       iterv2= uv_vertex_map_get(vmap, startefa, (starta+1)%nverts);
-       uv_vertex_loop_flag(iterv1);
-       uv_vertex_loop_flag(iterv2);
+       /* api callbacks */
+       ot->exec= set_2d_cursor_exec;
+       ot->invoke= set_2d_cursor_invoke;
+       ot->poll= ED_operator_uvedit;
 
-       starttotface= 0;
-       uv_edge_tag_faces(iterv1, iterv2, &starttotface);
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
-       /* sorry, first edge isnt even ok */
-       if(iterv1->flag==0 && iterv2->flag==0) looking= 0;
-       else looking= 1;
+       /* 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);
+}
 
-       /* iterate */
-       while(looking) {
-               looking= 0;
+/********************** set tile operator **********************/
 
-               /* find correct valence edges which are not tagged yet, but connect to tagged one */
-               for(efa= em->faces.first; efa; efa=efa->next) {
-                       tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+static int set_tile_exec(bContext *C, wmOperator *op)
+{
+       Image *ima= CTX_data_edit_image(C);
+       int tile[2];
 
-                       if(!efa->f1 && uvedit_face_visible(scene, ima, efa, tface)) {
-                               nverts= (efa->v4)? 4: 3;
-                               for(a=0; a<nverts; a++) {
-                                       /* check face not hidden and not tagged */
-                                       iterv1= uv_vertex_map_get(vmap, efa, a);
-                                       iterv2= uv_vertex_map_get(vmap, efa, (a+1)%nverts);
+       if(!ima || !(ima->tpageflag & IMA_TILES))
+               return OPERATOR_CANCELLED;
 
-                                       /* check if vertex is tagged and has right valence */
-                                       if(iterv1->flag || iterv2->flag) {
-                                               if(uv_edge_tag_faces(iterv1, iterv2, &starttotface)) {
-                                                       looking= 1;
-                                                       efa->f1= 1;
+       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]);
 
-                                                       uv_vertex_loop_flag(iterv1);
-                                                       uv_vertex_loop_flag(iterv2);
-                                                       break;
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
+       ED_area_tag_redraw(CTX_wm_area(C));
 
-       /* do the actual select/deselect */
-       nverts= (startefa->v4)? 4: 3;
-       iterv1= uv_vertex_map_get(vmap, startefa, starta);
-       iterv2= uv_vertex_map_get(vmap, startefa, (starta+1)%nverts);
-       iterv1->flag= 1;
-       iterv2->flag= 1;
+       return OPERATOR_FINISHED;
+}
 
-       if(shift) {
-               tface= CustomData_em_get(&em->fdata, startefa->data, CD_MTFACE);
-               if(uvedit_uv_selected(scene, startefa, tface, starta) && uvedit_uv_selected(scene, startefa, tface, starta))
-                       select= 0;
-               else
-                       select= 1;
+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);
        }
-       else
-               select= 1;
-       
-       if(select) *flush= 1;
-       else *flush= -1;
 
-       for(efa= em->faces.first; efa; efa=efa->next) {
-               tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+       return set_tile_exec(C, op);
+}
 
-               nverts= (efa->v4)? 4: 3;
-               for(a=0; a<nverts; a++) {
-                       iterv1= uv_vertex_map_get(vmap, efa, a);
+void UV_OT_tile_set(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Set Tile";
+       ot->idname= "UV_OT_tile_set";
+       
+       /* api callbacks */
+       ot->exec= set_tile_exec;
+       ot->invoke= set_tile_invoke;
+       ot->poll= ED_operator_uvedit;
 
-                       if(iterv1->flag) {
-                               if(select) uvedit_uv_select(scene, efa, tface, a);
-                               else uvedit_uv_deselect(scene, efa, tface, a);
-                       }
-               }
-       }
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 
-       /* cleanup */
-       EM_free_uv_vert_map(vmap);
-       EM_free_index_arrays();
+       /* 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_all_toggle);
        WM_operatortype_append(UV_OT_select_inverse);
+       WM_operatortype_append(UV_OT_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);
-       
-       WM_keymap_add_item(keymap, "UV_OT_de_select_all", AKEY, KM_PRESS, 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_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);
+
+       /* 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_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);
 }