2.5: uv editor
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Sat, 17 Jan 2009 22:14:08 +0000 (22:14 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Sat, 17 Jan 2009 22:14:08 +0000 (22:14 +0000)
- mouse select, loop select, select linked, unlink selection operators.
- added edge selection mode.
- fix 2.45 bug with unitialized theme colors, which caused the active face
  and face centers to be not drawn.

source/blender/blenloader/intern/readfile.c
source/blender/editors/interface/resources.c
source/blender/editors/space_image/image_header.c
source/blender/editors/space_image/space_image.c
source/blender/editors/uvedit/uvedit_draw.c
source/blender/editors/uvedit/uvedit_intern.h
source/blender/editors/uvedit/uvedit_ops.c
source/blender/makesdna/DNA_scene_types.h
source/blender/windowmanager/intern/wm_files.c

index 5224b51..e7c834e 100644 (file)
@@ -8492,8 +8492,12 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                        do_versions_windowmanager_2_50(screen);
                
                /* struct audio data moved to renderdata */
-               for(scene= main->scene.first; scene; scene= scene->id.next)
+               for(scene= main->scene.first; scene; scene= scene->id.next) {
                        scene->r.audio = scene->audio;
+
+                       if(!scene->toolsettings->uv_selectmode)
+                               scene->toolsettings->uv_selectmode= UV_SELECT_VERTEX;
+               }
                
                /* shader, composit and texture node trees have id.name empty, put something in
                 * to have them show in RNA viewer and accessible otherwise.
@@ -8501,7 +8505,8 @@ static void do_versions(FileData *fd, Library *lib, Main *main)
                for(ma= main->mat.first; ma; ma= ma->id.next) {
                        if(ma->nodetree && strlen(ma->nodetree->id.name)==0)
                                strcpy(ma->nodetree->id.name, "NTShader Nodetree");
-       }
+               }
+
                /* and composit trees */
                for(sce= main->scene.first; sce; sce= sce->id.next) {
                        if(sce->nodetree && strlen(sce->nodetree->id.name)==0)
index 0e74293..0152e34 100644 (file)
@@ -511,8 +511,10 @@ void ui_theme_init_userdef(void)
        SETCOL(btheme->tima.vertex, 0xff, 0x70, 0xff, 255);
        SETCOL(btheme->tima.vertex_select, 0xff, 0xff, 0x70, 255);
        btheme->tima.vertex_size= 2;
+       btheme->tima.facedot_size= 2;
        SETCOL(btheme->tima.face,   0, 50, 150, 40);
        SETCOL(btheme->tima.face_select, 200, 100, 200, 80);
+       SETCOL(btheme->tima.editmesh_active, 255, 255, 255, 128);
 
        /* space imageselect */
        btheme->timasel= btheme->tv3d;
index 6991d7f..9c99a19 100644 (file)
@@ -223,12 +223,6 @@ static void do_selectmenu(bContext *C, void *arg, int event)
        case 8: /* Border Select Pinned */
                borderselect_sima(UV_SELECT_PINNED);
                break;
-       case 2: /* Unlink Selection */
-               unlink_selection();
-               break;
-       case 3: /* Linked UVs */
-               select_linked_tface_uv(2);
-               break;
        case 7: /* Pinned UVs */
                select_pinned_tface_uv();
                break;
@@ -1207,9 +1201,11 @@ void image_header_buttons(const bContext *C, ARegion *ar)
                        uiBlockBeginAlign(block);
                        
                        uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_REDR, ICON_VERTEXSEL,
-                               xco,yco,XIC,YIC, &scene->selectmode, 1.0, 0.0, 0, 0, "Vertex select mode (Ctrl Tab 1)");
+                               xco,yco,XIC,YIC, &scene->selectmode, 1.0, 0.0, 0, 0, "Vertex select mode");
+                       uiDefIconButBitS(block, TOG, SCE_SELECT_EDGE, B_REDR, ICON_EDGESEL,
+                               xco+=XIC,yco,XIC,YIC, &scene->selectmode, 1.0, 0.0, 0, 0, "Edge select mode");
                        uiDefIconButBitS(block, TOG, SCE_SELECT_FACE, B_REDR, ICON_FACESEL,
-                               xco+=XIC,yco,XIC,YIC, &scene->selectmode, 1.0, 0.0, 0, 0, "Face select mode (Ctrl Tab 3)");
+                               xco+=XIC,yco,XIC,YIC, &scene->selectmode, 1.0, 0.0, 0, 0, "Face select mode");
 
                        uiBlockEndAlign(block);
                }
@@ -1218,6 +1214,8 @@ void image_header_buttons(const bContext *C, ARegion *ar)
 
                        uiDefIconButS(block, ROW, B_REDR, ICON_VERTEXSEL,
                                xco,yco,XIC,YIC, &scene->toolsettings->uv_selectmode, 1.0, UV_SELECT_VERTEX, 0, 0, "Vertex select mode");
+                       uiDefIconButS(block, ROW, B_REDR, ICON_EDGESEL,
+                               xco+=XIC,yco,XIC,YIC, &scene->toolsettings->uv_selectmode, 1.0, UV_SELECT_EDGE, 0, 0, "Edge select mode");
                        uiDefIconButS(block, ROW, B_REDR, ICON_FACESEL,
                                xco+=XIC,yco,XIC,YIC, &scene->toolsettings->uv_selectmode, 1.0, UV_SELECT_FACE, 0, 0, "Face select mode");
                        uiDefIconButS(block, ROW, B_REDR, ICON_MESH,
index 893ace0..feeb09e 100644 (file)
@@ -493,7 +493,7 @@ ImBuf *get_space_image_buffer(SpaceImage *sima)
 #endif
                        ibuf= BKE_image_get_ibuf(sima->image, &sima->iuser);
 
-               if(ibuf->rect || ibuf->rect_float)
+               if(ibuf && (ibuf->rect || ibuf->rect_float))
                        return ibuf;
        }
 
index d363639..ddb45bd 100644 (file)
@@ -412,25 +412,26 @@ static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFac
 /* draws uv's in the image space */
 static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
 {
+       ToolSettings *settings;
        EditMesh *em;
        EditFace *efa, *efa_act;
        MTFace *tf, *activetf = NULL;
        DerivedMesh *finaldm, *cagedm;
        char col1[4], col2[4];
        float pointsize;
-       int drawfaces, lastsel, sel;
+       int drawfaces, interpedges, lastsel, sel;
        Image *ima= sima->image;
        
        em= ((Mesh*)obedit->data)->edit_mesh;
        activetf= EM_get_active_mtface(em, &efa_act, NULL, 0); /* will be set to NULL if hidden */
 
+       settings= scene->toolsettings;
+
        drawfaces= draw_uvs_face_check(scene);
-       
-#if 0
-       calc_image_view(G.sima, 'f');   /* float */
-       myortho2(G.v2d->cur.xmin, G.v2d->cur.xmax, G.v2d->cur.ymin, G.v2d->cur.ymax);
-       glLoadIdentity();
-#endif
+       if(settings->uv_flag & UV_SYNC_SELECTION)
+               interpedges= (scene->selectmode & SCE_SELECT_VERTEX);
+       else
+               interpedges= (settings->uv_selectmode == UV_SELECT_VERTEX);
 
        /* 1. draw shadow mesh */
        
@@ -442,7 +443,7 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
 
                        /* when sync selection is enabled, all faces are drawn (except for hidden)
                         * so if cage is the same as the final, theres no point in drawing this */
-                       if(!((scene->toolsettings->uv_flag & UV_SYNC_SELECTION) && (cagedm == finaldm)))
+                       if(!((settings->uv_flag & UV_SYNC_SELECTION) && (cagedm == finaldm)))
                                draw_uvs_dm_shadow(finaldm);
                        
                        /* release derivedmesh again */
@@ -614,37 +615,75 @@ static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
                        glColor4ubv((unsigned char *)col2); 
                        
                        if(G.f & G_DRAWEDGES) {
-                               glShadeModel(GL_SMOOTH);
                                UI_GetThemeColor4ubv(TH_VERTEX_SELECT, col1);
                                lastsel = sel = 0;
 
-                               for(efa= em->faces.first; efa; efa= efa->next) {
-                                       tf= (MTFace *)efa->tmp.p; /* visible faces cached */
+                               if(interpedges) {
+                                       glShadeModel(GL_SMOOTH);
 
-                                       if(tf) {
-                                               glBegin(GL_LINE_LOOP);
-                                               sel = (uvedit_uv_selected(scene, efa, tf, 0) ? 1 : 0);
-                                               if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
-                                               glVertex2fv(tf->uv[0]);
-                                               
-                                               sel = uvedit_uv_selected(scene, efa, tf, 1) ? 1 : 0;
-                                               if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
-                                               glVertex2fv(tf->uv[1]);
-                                               
-                                               sel = uvedit_uv_selected(scene, efa, tf, 2) ? 1 : 0;
-                                               if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
-                                               glVertex2fv(tf->uv[2]);
-                                               
-                                               if(efa->v4) {
-                                                       sel = uvedit_uv_selected(scene, efa, tf, 3) ? 1 : 0;
+                                       for(efa= em->faces.first; efa; efa= efa->next) {
+                                               tf= (MTFace *)efa->tmp.p; /* visible faces cached */
+
+                                               if(tf) {
+                                                       glBegin(GL_LINE_LOOP);
+                                                       sel = (uvedit_uv_selected(scene, efa, tf, 0)? 1 : 0);
+                                                       if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
+                                                       glVertex2fv(tf->uv[0]);
+                                                       
+                                                       sel = uvedit_uv_selected(scene, efa, tf, 1)? 1 : 0;
+                                                       if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
+                                                       glVertex2fv(tf->uv[1]);
+                                                       
+                                                       sel = uvedit_uv_selected(scene, efa, tf, 2)? 1 : 0;
                                                        if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
-                                                       glVertex2fv(tf->uv[3]);
+                                                       glVertex2fv(tf->uv[2]);
+                                                       
+                                                       if(efa->v4) {
+                                                               sel = uvedit_uv_selected(scene, efa, tf, 3)? 1 : 0;
+                                                               if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
+                                                               glVertex2fv(tf->uv[3]);
+                                                       }
+                                                       
+                                                       glEnd();
+                                               }
+                                       }
+
+                                       glShadeModel(GL_FLAT);
+                               }
+                               else {
+                                       for(efa= em->faces.first; efa; efa= efa->next) {
+                                               tf= (MTFace *)efa->tmp.p; /* visible faces cached */
+
+                                               if(tf) {
+                                                       glBegin(GL_LINES);
+                                                       sel = (uvedit_edge_selected(scene, efa, tf, 0)? 1 : 0);
+                                                       if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
+                                                       glVertex2fv(tf->uv[0]);
+                                                       glVertex2fv(tf->uv[1]);
+                                                       
+                                                       sel = uvedit_edge_selected(scene, efa, tf, 1)? 1 : 0;
+                                                       if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
+                                                       glVertex2fv(tf->uv[1]);
+                                                       glVertex2fv(tf->uv[2]);
+                                                       
+                                                       sel = uvedit_edge_selected(scene, efa, tf, 2)? 1 : 0;
+                                                       if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
+                                                       glVertex2fv(tf->uv[2]);
+                                                       
+                                                       if(efa->v4) {
+                                                               glVertex2fv(tf->uv[3]);
+
+                                                               sel = uvedit_edge_selected(scene, efa, tf, 3)? 1 : 0;
+                                                               if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
+                                                               glVertex2fv(tf->uv[3]);
+                                                       }
+
+                                                       glVertex2fv(tf->uv[0]);
+                                                       
+                                                       glEnd();
                                                }
-                                               
-                                               glEnd();
                                        }
                                }
-                               glShadeModel(GL_FLAT);
                        }
                        else {
                                /* no nice edges */
index 99656bf..ea18884 100644 (file)
@@ -56,6 +56,10 @@ int uvedit_face_selected(struct Scene *scene, struct EditFace *efa, struct MTFac
 void uvedit_face_select(struct Scene *scene, struct EditFace *efa, struct MTFace *tf);
 void uvedit_face_deselect(struct Scene *scene, struct EditFace *efa, struct MTFace *tf);
 
+int uvedit_edge_selected(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
+void uvedit_edge_select(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
+void uvedit_edge_deselect(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
+
 int uvedit_uv_selected(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
 void uvedit_uv_select(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
 void uvedit_uv_deselect(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
index e097511..2e5f64a 100644 (file)
@@ -28,6 +28,7 @@
  */
 
 #include <stdlib.h>
+#include <string.h>
 #include <math.h>
 
 #include "MEM_guardedalloc.h"
@@ -50,6 +51,7 @@
 #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 "WM_api.h"
 #include "WM_types.h"
 
+#include "UI_view2d.h"
+
 #include "uvedit_intern.h"
 
 /* local prototypes */
 static void sel_uvco_inside_radius(SpaceImage *sima, Scene *scene, short sel, EditFace *efa, MTFace *tface, int index, float *offset, float *ell, short select_index);
 void uvedit_selectionCB(SpaceImage *sima, Scene *scene, ARegion *ar, short selecting, Object *obedit, short *mval, float rad); /* used in edit.c */
-void 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);
 
 /************************* state testing ************************/
@@ -187,9 +189,9 @@ void ED_uvedit_set_tile(Scene *scene, Object *obedit, Image *ima, int curtile, i
        // XXX WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
 }
 
-/*********************** connection testing *********************/
+/*********************** space conversion *********************/
 
-static void uvedit_connection_limit(bContext *C, float *limit, float pixellimit)
+static void uvedit_pixel_to_float(bContext *C, float *dist, float pixeldist)
 {
        ImBuf *ibuf= CTX_data_edit_image_buffer(C);
        float width, height;
@@ -203,8 +205,8 @@ static void uvedit_connection_limit(bContext *C, float *limit, float pixellimit)
                height= 256.0f;
        }
 
-       limit[0]= pixellimit/width;
-       limit[1]= pixellimit/height;
+       dist[0]= pixeldist/width;
+       dist[1]= pixeldist/height;
 }
 
 /*************** visibility and selection utilities **************/
@@ -249,6 +251,58 @@ void uvedit_face_deselect(Scene *scene, EditFace *efa, MTFace *tf)
                tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
 }
 
+int uvedit_edge_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
+{
+       int nvert= (efa->v4)? 4: 3;
+
+       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
+               if(scene->selectmode == SCE_SELECT_FACE)
+                       return (efa->f & SELECT);
+               else if(scene->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)
+{
+       int nvert= (efa->v4)? 4: 3;
+
+       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
+               if(scene->selectmode == SCE_SELECT_FACE)
+                       EM_select_face(efa, 1);
+               else if(scene->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)
+{
+       int nvert= (efa->v4)? 4: 3;
+
+       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
+               if(scene->selectmode == SCE_SELECT_FACE)
+                       EM_select_face(efa, 0);
+               else if(scene->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) {
@@ -445,178 +499,649 @@ void uvedit_constrain_square(Scene *scene, Image *ima, EditMesh *em)
        }
 }
 
-/* ******************** mirror operator **************** */
+/************************** find nearest ****************************/
 
-/* XXX */
-#if 0
-       short mode= 0;
-       mode= pupmenu("Mirror%t|X Axis%x1|Y Axis%x2|");
-#endif
+typedef struct NearestHit {
+       EditFace *efa;
+       MTFace *tf;
 
-static int mirror_exec(bContext *C, wmOperator *op)
+       int vert, uv;
+       int edge, vert2;
+} NearestHit;
+
+static void find_nearest_uv_edge(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
 {
-       float mat[3][3];
-       int axis;
+       MTFace *tf;
+       EditFace *efa;
+       EditVert *eve;
+       float mindist, dist;
+       int i, nverts;
+
+       mindist= 1e10f;
+       memset(hit, 0, sizeof(*hit));
+
+       for(i=0, eve=em->verts.first; eve; eve=eve->next, i++)
+               eve->tmp.l = i;
        
-       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;
 
-       return OPERATOR_FINISHED;
+                       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;
+                               }
+                       }
+               }
+       }
 }
 
-void UV_OT_mirror(wmOperatorType *ot)
+static void find_nearest_uv_face(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
 {
-       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}};
+       MTFace *tf;
+       EditFace *efa;
+       float mindist, dist, cent[2];
+       int i, nverts;
 
-       /* identifiers */
-       ot->name= "Mirror";
-       ot->idname= "UV_OT_mirror";
-       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       mindist= 1e10f;
+       memset(hit, 0, sizeof(*hit));
        
-       /* api callbacks */
-       ot->exec= mirror_exec;
-       ot->poll= ED_operator_uvedit;
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 
-       /* properties */
-       RNA_def_enum(ot->srna, "axis", axis_items, 'x', "Axis", "Axis to mirror UV locations over.");
-}
+               if(uvedit_face_visible(scene, ima, efa, tf)) {
+                       nverts= efa->v4? 4: 3;
+                       cent[0]= cent[1]= 0.0f;
 
-/* ******************** align operator **************** */
+                       for(i=0; i<nverts; i++) {
+                               cent[0] += tf->uv[i][0];
+                               cent[1] += tf->uv[i][1];
+                       }
 
-/* XXX */
-#if 0
-void weld_align_menu_tface_uv(bContext *C)
+                       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;
+                       }
+               }
+       }
+}
+
+static int nearest_uv_between(MTFace *tf, int nverts, int id, float co[2], float uv[2])
 {
-       short mode= 0;
+       float m[3], v1[3], v2[3], c1, c2;
+       int id1, id2;
 
-       mode= pupmenu("Weld/Align%t|Weld%x1|Align Auto%x2|Align X%x3|Align Y%x4");
+       id1= (id+nverts-1)%nverts;
+       id2= (id+nverts+1)%nverts;
 
-       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');
+       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]);
+
+       /* 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];
+
+       if(c1*c2 < 0.0f)
+               return 0;
+
+       /* 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];
+
+       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];
-       
-       scene= CTX_data_scene(C);
-       obedit= CTX_data_edit_object(C);
-       em= ((Mesh*)obedit->data)->edit_mesh;
-       ima= CTX_data_edit_image(C);
+       float mindist, dist;
+       int i, nverts;
 
-       INIT_MINMAX2(min, max);
+       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(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)) {
+                       nverts= efa->v4? 4: 3;
 
-                       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)
-                       }
-               }
+                       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]);
 
-               tool= (max[0]-min[0] >= max[1]-min[1])? 'y': 'x';
-       }
+                               if(dist<=mindist) {
+                                       if(dist==mindist)
+                                               if(!nearest_uv_between(tf, nverts, i, co, tf->uv[i]))
+                                                       continue;
 
-       uvedit_center(scene, ima, obedit, cent, 0);
+                                       mindist= dist;
 
-       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->uv= i;
+                                       hit->tf= tf;
+                                       hit->efa= efa;
 
-       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];
+                                       hit->vert= (*(&efa->v1 + i))->tmp.l;
+                               }
                        }
                }
        }
-
-       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
-       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); // XXX
 }
 
-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);
+}
+
+/* ******************** mirror operator **************** */
+
+/* XXX */
+#if 0
+       short mode= 0;
+       mode= pupmenu("Mirror%t|X Axis%x1|Y Axis%x2|");
+#endif
+
+static int mirror_exec(bContext *C, wmOperator *op)
+{
+       float mat[3][3];
+       int axis;
+       
+       Mat3One(mat);
+       axis= RNA_enum_get(op->ptr, "axis");
+
+       if(axis == 'x') {
+               /* XXX initTransform(TFM_MIRROR, CTX_NO_PET|CTX_AUTOCONFIRM);
+               BIF_setSingleAxisConstraint(mat[0], " on X axis");
+               Transform(); */
+       }
+       else {
+               /* XXX initTransform(TFM_MIRROR, CTX_NO_PET|CTX_AUTOCONFIRM);
+               BIF_setSingleAxisConstraint(mat[1], " on Y axis");
+               Transform(); */
+       }
+
+       return OPERATOR_FINISHED;
+}
+
+void UV_OT_mirror(wmOperatorType *ot)
+{
+       static EnumPropertyItem axis_items[] = {
+               {'x', "MIRROR_X", "Mirror X", "Mirror UVs over X axis."},
+               {'y', "MIRROR_Y", "Mirror Y", "Mirror UVs over Y axis."},
+               {0, NULL, NULL, NULL}};
+
+       /* identifiers */
+       ot->name= "Mirror";
+       ot->idname= "UV_OT_mirror";
+       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       
+       /* api callbacks */
+       ot->exec= mirror_exec;
+       ot->poll= ED_operator_uvedit;
+
+       /* properties */
+       RNA_def_enum(ot->srna, "axis", axis_items, 'x', "Axis", "Axis to mirror UV locations over.");
+}
+
+/* ******************** align operator **************** */
+
+/* XXX */
+#if 0
+void weld_align_menu_tface_uv(bContext *C)
+{
+       short mode= 0;
+
+       mode= pupmenu("Weld/Align%t|Weld%x1|Align Auto%x2|Align X%x3|Align Y%x4");
+
+       if(mode==-1) return;
+       if(mode==1) weld_align_uv(C, 'w');
+       else if(mode==2) weld_align_uv(C, 'a');
+       else if(mode==3) weld_align_uv(C, 'x');
+       else if(mode==4) weld_align_uv(C, 'y');
+}
+#endif
+
+static void weld_align_uv(bContext *C, int tool)
+{
+       Scene *scene;
+       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= ((Mesh*)obedit->data)->edit_mesh;
+       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_object_flush_update(scene, obedit, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit); // XXX
+}
+
+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", "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*/;
+       
+       /* 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');
@@ -666,7 +1191,7 @@ static int stitch_exec(bContext *C, wmOperator *op)
                int a, vtot;
 
                pixels= RNA_float_get(op->ptr, "limit");
-               uvedit_connection_limit(C, limit, pixels);
+               uvedit_pixel_to_float(C, limit, pixels);
 
                EM_init_index_arrays(em, 0, 0, 1);
                vmap= EM_make_uv_vert_map(em, 1, 0, limit);
@@ -941,328 +1466,200 @@ void UV_OT_de_select_all(wmOperatorType *ot)
 
 /* ******************** mouse select operator **************** */
 
-static int msel_hit(float *limit, unsigned int *hitarray, unsigned int vertexid, float **uv, float *uv2, int sticky)
+static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, 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])
+
+       /* 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 return 1;
+                       else if(sticky == SI_STICKY_VERTEX)
+                               return 1;
                }
        }
+
        return 0;
 }
 
-static void find_nearest_uv_edge(Scene *scene, Image *ima, Object *obedit, MTFace **nearesttf, EditFace **nearestefa, int *nearestedge)
+static int mouse_select(bContext *C, float co[2], int extend, int loop)
 {
+       SpaceImage *sima= (SpaceImage*)CTX_wm_space_data(C);
+       Scene *scene= CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       Image *ima= CTX_data_edit_image(C);
        EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
-       MTFace *tf;
        EditFace *efa;
-       float mvalf[2], v1[2], v2[2];
-       int i, nverts, mindist, dist, uval1[2], uval2[2];
-       short mval[2];
-
-       mval[0]= mval[1]= 0; // XXX getmouseco_areawin(mval);
-       mvalf[0]= mval[0];
-       mvalf[1]= mval[1];
-
-       mindist= 0x7FFFFFF;
-       *nearesttf= NULL;
-       *nearestefa= NULL;
-       *nearestedge= 0;
+       MTFace *tf;
+       NearestHit hit;
+       int a, i, select, 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];
        
-       for(efa= em->faces.first; efa; efa= efa->next) {
-               tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+       uvedit_pixel_to_float(C, limit, 0.05f);
+       uvedit_pixel_to_float(C, penalty, 5.0f);
 
-               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);
+       /* retrieve operation mode */
+       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
+               sync= 1;
 
-                               v1[0]= uval1[0];
-                               v1[1]= uval1[1];
-                               v2[0]= uval2[0];
-                               v2[1]= uval2[1];
+               if(scene->selectmode & SCE_SELECT_FACE)
+                       selectmode= UV_SELECT_FACE;
+               else if(scene->selectmode & SCE_SELECT_EDGE)
+                       selectmode= UV_SELECT_EDGE;
+               else
+                       selectmode= UV_SELECT_VERTEX;
 
-                               dist= PdistVL2Dfl(mvalf, v1, v2);
-                               if(dist < mindist) {
-                                       *nearesttf= tf;
-                                       *nearestefa= efa;
-                                       *nearestedge= i;
-                                       mindist= dist;
-                               }
-                       }
-               }
+               sticky= SI_STICKY_DISABLE;
        }
-}
-
-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);   
-
-       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];
-                       }
-
-                       fcenter[0] /= nverts;
-                       fcenter[1] /= nverts;
+       else {
+               sync= 0;
+               selectmode= scene->toolsettings->uv_selectmode;
+               sticky= sima->sticky;
 
-                       dist= abs(mval[0]- fcenter[0])+ abs(mval[1]- fcenter[1]);
-                       if(dist < mindist) {
-                               *nearesttf= tf;
-                               *nearestefa= efa;
-                               mindist= dist;
-                       }
-               }
+               /* XXX if(sticky == SI_STICKY_VERTEX && (G.qual & LR_CTRLKEY))
+                       sticky= SI_STICKY_DISABLE;*/
        }
-}
-
-static int nearest_uv_between(MTFace *tf, int nverts, int id, short *mval, int *uval)
-{
-       float m[3], v1[3], v2[3], c1, c2;
-       int id1, id2;
-
-       id1= (id+nverts-1)%nverts;
-       id2= (id+nverts+1)%nverts;
-
-       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]);
-
-       /* 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];
-
-       if(c1*c2 < 0.0f)
-               return 0;
-
-       /* 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];
-
-       return (c1*c2 >= 0.0f);
-}
-
-void find_nearest_uv(Scene *scene, Image *ima, Object *obedit, MTFace **nearesttf, EditFace **nearestefa, unsigned int *nearestv, int *nearestuv)
-{
-       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
-       EditFace *efa;
-       MTFace *tf;
-       int i, nverts, mindist, dist, uval[2];
-       short mval[2];
-
-       mval[0]= mval[1]= 0; // XXX getmouseco_areawin(mval);   
 
-       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;
+       /* find nearest element */
+       if(loop) {
+               /* find edge */
+               find_nearest_uv_edge(scene, ima, em, co, &hit);
+               if(hit.efa == NULL)
+                       return OPERATOR_CANCELLED;
        }
-       
-       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]);
-
-                               if(uvedit_uv_selected(scene, efa, tf, i))
-                                       dist += 5;
+       else if(selectmode == UV_SELECT_VERTEX) {
+               /* find vertex */
+               find_nearest_uv_vert(scene, ima, em, co, penalty, &hit);
+               if(hit.efa == NULL)
+                       return OPERATOR_CANCELLED;
 
-                               if(dist<=mindist) {
-                                       if(dist==mindist)
-                                               if(!nearest_uv_between(tf, nverts, i, mval, uval))
-                                                       continue;
+               /* mark 1 vertex as being hit */
+               for(i=0; i<4; i++)
+                       hitv[i]= 0xFFFFFFFF;
 
-                                       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;
-                                       }
-                               }
-                       }
-               }
+               hitv[hit.uv]= hit.vert;
+               hituv[hit.uv]= hit.tf->uv[hit.uv];
        }
-}
-
-void mouse_select_sima(bContext *C, SpaceImage *sima, Scene *scene, Image *ima, Object *obedit)
-{
-       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];
-       
-       if(!uvedit_test(obedit)) return;
+       else if(selectmode == UV_SELECT_EDGE) {
+               /* find edge */
+               find_nearest_uv_edge(scene, ima, em, co, &hit);
+               if(hit.efa == NULL)
+                       return OPERATOR_CANCELLED;
 
-       uvedit_connection_limit(C, limit, 0.05);
-       
-       edgeloop= 0; // XXX G.qual & LR_ALTKEY;
-       shift= 0; // XXX G.qual & LR_SHIFTKEY;
-       
-       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;
-               }
-       }
+               /* mark 2 edge vertices as being hit */
+               for(i=0; i<4; i++)
+                       hitv[i]= 0xFFFFFFFF;
 
-       if(edgeloop) {
-               find_nearest_uv_edge(scene, ima, obedit, &nearesttf, &nearestefa, &nearestedge);
-               if(nearesttf==NULL)
-                       return;
+               nvert= (hit.efa->v4)? 4: 3;
 
-               select_edgeloop_tface_uv(C, scene, ima, obedit, nearestefa, nearestedge, shift, &flush);
+               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(actface) {
-               find_nearest_tface(scene, ima, obedit, &nearesttf, &nearestefa);
-               if(nearesttf==NULL)
-                       return;
+       else if(selectmode == UV_SELECT_FACE) {
+               /* find face */
+               find_nearest_uv_face(scene, ima, em, co, &hit);
+               if(hit.efa == NULL)
+                       return OPERATOR_CANCELLED;
                
-               EM_set_actFace(em, nearestefa);
+               /* make active */
+               EM_set_actFace(em, hit.efa);
 
+               /* mark all face vertices as being hit */
                for(i=0; i<4; i++)
-                       hituv[i]= nearesttf->uv[i];
+                       hituv[i]= hit.tf->uv[i];
 
-               hitv[0]= nearestefa->v1->tmp.l;
-               hitv[1]= nearestefa->v2->tmp.l;
-               hitv[2]= nearestefa->v3->tmp.l;
+               hitv[0]= hit.efa->v1->tmp.l;
+               hitv[1]= hit.efa->v2->tmp.l;
+               hitv[2]= hit.efa->v3->tmp.l;
                
-               if(nearestefa->v4)      hitv[3]= nearestefa->v4->tmp.l;
-               else                            hitv[3]= 0xFFFFFFFF;
+               if(hit.efa->v4) hitv[3]= hit.efa->v4->tmp.l;
+               else hitv[3]= 0xFFFFFFFF;
        }
-       else if(island) {
+       else if(selectmode == UV_SELECT_ISLAND) {
+               find_nearest_uv_vert(scene, ima, em, co, NULL, &hit);
 
+               if(hit.efa==NULL)
+                       return OPERATOR_CANCELLED;
        }
-       else {
-               find_nearest_uv(scene, ima, obedit, &nearesttf, &nearestefa, &nearestv, &nearestuv);
-               if(nearesttf==NULL)
-                       return;
+       else
+               return OPERATOR_CANCELLED;
 
-               if(sticky) {
-                       for(i=0; i<4; i++)
-                               hitv[i]= 0xFFFFFFFF;
-                       hitv[nearestuv]= nearestv;
-                       hituv[nearestuv]= nearesttf->uv[nearestuv];
-               }
+       /* do selection */
+       if(loop) {
+               flush= select_edgeloop(scene, ima, em, &hit, limit, extend);
        }
-
-       if(island) {
-               if(shift) select_linked_tface_uv(C, scene, ima, obedit, 1);
-               else select_linked_tface_uv(C, scene, ima, obedit, 0);
+       else if(selectmode == UV_SELECT_ISLAND) {
+               select_linked(scene, ima, em, limit, &hit, extend);
        }
-       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 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_face_select(scene, nearestefa, nearesttf);
-                               selectsticky= 1;
+                               uvedit_uv_select(scene, hit.efa, hit.tf, hit.uv);
+                               select= 1;
                        }
-                       flush = -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 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_uv_select(scene, nearestefa, nearesttf, nearestuv);
-                               selectsticky= 1;
+                               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 || actface) {
+               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(selectsticky==0) {
+                       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(nearesttf && tf!=nearesttf) tf->flag &=~ TF_ACTIVE;*/ /* TODO - deal with editmesh active face */
-                                               if(!sticky) continue;
-       
-                                               if(msel_hit(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
+                                               if(sticky_select(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))
+                                               if(sticky_select(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))
+                                               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(msel_hit(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
+                                                       if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
                                                                uvedit_uv_deselect(scene, efa, tf, 3);
                                        }
                                }
@@ -1272,82 +1669,274 @@ void mouse_select_sima(bContext *C, SpaceImage *sima, Scene *scene, Image *ima,
                        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))
+                                               if(sticky_select(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))
+                                               if(sticky_select(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))
+                                               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(msel_hit(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
+                                                       if(sticky_select(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);
-                       }
-                               
-               }
+       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(scene->selectmode != SCE_SELECT_FACE) {
+                       if(flush==1)            EM_select_flush(em);
+                       else if(flush==-1)      EM_deselect_flush(em);
+               }
+       }
+       
+       // XXX force_draw(1);
+       // XXX BIF_undo_push("Select UV");
+       // XXX rightmouse_transform();
+
+       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+       return 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);
+
+       return select_exec(C, op);
+}
+
+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;
+
+       /* 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);
+}
+
+/* ******************** loop select operator **************** */
+
+static int loop_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= 1;
+
+       return mouse_select(C, co, extend, loop);
+}
+
+static int loop_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);
+
+       return loop_select_exec(C, op);
+}
+
+void UV_OT_loop_select(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Loop Select";
+       ot->idname= "UV_OT_loop_select";
+       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       
+       /* api callbacks */
+       ot->exec= loop_select_exec;
+       ot->invoke= loop_select_invoke;
+       ot->poll= ED_operator_uvedit;
+
+       /* 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);
+}
+
+/* ******************** linked select operator **************** */
+
+static int select_linked_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       Image *ima= CTX_data_edit_image(C);
+       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       float limit[2];
+       int extend;
+
+       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
+               BKE_report(op->reports, RPT_ERROR, "Can't select linked when sync selection is enabled.");
+               return OPERATOR_CANCELLED;
+       }
+
+       extend= RNA_boolean_get(op->ptr, "extend");
+       uvedit_pixel_to_float(C, 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);
+
+       return OPERATOR_FINISHED;
+}
+
+void UV_OT_select_linked(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Select Linked";
+       ot->idname= "UV_OT_select_linked";
+       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
+       
+       /* api callbacks */
+       ot->exec= select_linked_exec;
+       ot->poll= ED_operator_uvedit;
+
+       /* properties */
+       RNA_def_boolean(ot->srna, "extend", 0,
+               "Extend", "Extend selection rather than clearing the existing selection.");
+}
+
+/* ******************** unlink selection operator **************** */
+
+static int unlink_selection_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene= CTX_data_scene(C);
+       Object *obedit= CTX_data_edit_object(C);
+       Image *ima= CTX_data_edit_image(C);
+       EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
+       EditFace *efa;
+       MTFace *tf;
+
+       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
+               BKE_report(op->reports, RPT_ERROR, "Can't unlink selection when sync selection is enabled.");
+               return OPERATOR_CANCELLED;
+       }
+       
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 
-               /* 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(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);
                        }
-               }
-               
-               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 */
-       }
+       DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
+       WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
+
+       return OPERATOR_FINISHED;
+}
+
+void UV_OT_unlink_selection(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name= "Unlink Selection";
+       ot->idname= "UV_OT_unlink_selection";
+       ot->flag= OPTYPE_REGISTER/*|OPTYPE_UNDO*/;
        
-       // XXX BIF_undo_push("Select UV");
-       // XXX rightmouse_transform();
+       /* api callbacks */
+       ot->exec= unlink_selection_exec;
+       ot->poll= ED_operator_uvedit;
 }
 
+/* ******************** border select operator **************** */
+
 void borderselect_sima(bContext *C, SpaceImage *sima, Scene *scene, Image *ima, Object *obedit, short whichuvs)
 {
        EditMesh *em= ((Mesh*)obedit->data)->edit_mesh;
@@ -1707,255 +2296,77 @@ static void sel_uvco_inside_radius(SpaceImage *sima, Scene *scene, short sel, Ed
        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(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);
-               }
-       }
-       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;
-                       }
-               }
-
-               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);
-                               }
-                       }
-               }
+       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);
        }
-       
-       MEM_freeN(stack);
-       MEM_freeN(flag);
-       EM_free_uv_vert_map(vmap);
+}
 
-       // XXX BIF_undo_push("Select linked UV");
-       // XXX scrarea_queue_winredraw(curarea);
+// 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;
 }
 
-void unlink_selection(Scene *scene, Image *ima, Object *obedit)
+/** 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
 
-       if(!uvedit_test(obedit)) return;
+       getSpaceImageDimension(sima, ar, ellipse);
+       ellipse[0] /= rad;
+       ellipse[1] /= rad;
 
-       if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
-               ; // XXX error("Can't select unlinked when Sync Mesh Selection is enabled");
-               return;
-       }
+       // XXX areamouseco_to_ipoco(G.v2d, mval, &offset[0], &offset[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(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(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);
        }
-       
-       // XXX BIF_undo_push("Unlink UV selection");
-       // XXX scrarea_queue_winredraw(curarea);
 }
 
 /* this function sets the selection on tagged faces
@@ -2026,7 +2437,7 @@ void uvface_setsel__internal(bContext *C, SpaceImage *sima, Scene *scene, Object
                //EditVert *eve; /* removed vert counting for now */ 
                //int a;
                
-               uvedit_connection_limit(C, limit, 0.05);
+               uvedit_pixel_to_float(C, limit, 0.05);
                
                EM_init_index_arrays(em, 0, 0, 1);
                vmap= EM_make_uv_vert_map(em, 0, 0, limit);
@@ -2159,214 +2570,16 @@ void select_pinned_tface_uv(Scene *scene, Image *ima, Object *obedit)
        // XXX scrarea_queue_winredraw(curarea);
 }
 
-/* UV edge loop select, follows same rules as editmesh */
-
-static void uv_vertex_loop_flag(UvMapVert *first)
-{
-       UvMapVert *iterv;
-       int count= 0;
-
-       for(iterv=first; iterv; iterv=iterv->next) {
-               if(iterv->separate && iterv!=first)
-                       break;
-
-               count++;
-       }
-       
-       if(count < 5)
-               first->flag= 1;
-}
-
-static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, EditFace *efa, int a)
-{
-       UvMapVert *iterv, *first;
-       
-       first= EM_get_uv_map_vert(vmap, (*(&efa->v1 + a))->tmp.l);
-
-       for(iterv=first; iterv; iterv=iterv->next) {
-               if(iterv->separate)
-                       first= iterv;
-               if(iterv->f == efa->tmp.l)
-                       return first;
-       }
-       
-       return NULL;
-}
-
-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;
-}
-
-void select_edgeloop_tface_uv(bContext *C, Scene *scene, Image *ima, Object *obedit, EditFace *startefa, int starta, int shift, int *flush)
-{
-       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;
-       
-       if(!uvedit_test(obedit)) return;
-
-       /* setup */
-       EM_init_index_arrays(em, 0, 0, 1);
-
-       uvedit_connection_limit(C, limit, 0.05);
-       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(!shift) {
-                       tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-                       uvedit_face_deselect(scene, efa, tface);
-               }
-
-               efa->tmp.l= count;
-               efa->f1= 0;
-       }
-       
-       /* 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);
-
-       starttotface= 0;
-       uv_edge_tag_faces(iterv1, iterv2, &starttotface);
-
-       /* 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) {
-                       tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
-
-                       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);
-
-                                       /* 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;
-
-                                                       uv_vertex_loop_flag(iterv1);
-                                                       uv_vertex_loop_flag(iterv2);
-                                                       break;
-                                               }
-                                       }
-                               }
-                       }
-               }
-       }
-
-       /* 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;
-
-       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;
-       }
-       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);
-
-               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, tface, a);
-                               else uvedit_uv_deselect(scene, efa, tface, a);
-                       }
-               }
-       }
-
-       /* cleanup */
-       EM_free_uv_vert_map(vmap);
-       EM_free_index_arrays();
-}
-
 /* ************************** registration **********************************/
 
 void ED_operatortypes_uvedit(void)
 {
        WM_operatortype_append(UV_OT_de_select_all);
        WM_operatortype_append(UV_OT_select_inverse);
+       WM_operatortype_append(UV_OT_select);
+       WM_operatortype_append(UV_OT_loop_select);
+       WM_operatortype_append(UV_OT_select_linked);
+       WM_operatortype_append(UV_OT_unlink_selection);
 
        WM_operatortype_append(UV_OT_align);
        WM_operatortype_append(UV_OT_mirror);
@@ -2378,6 +2591,14 @@ void ED_keymap_uvedit(wmWindowManager *wm)
 {
        ListBase *keymap= WM_keymap_listbase(wm, "UVEdit", 0, 0);
        
+       WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, 0, 0);
+       RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, 0)->ptr, "extend", 1);
+       WM_keymap_add_item(keymap, "UV_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_ALT, 0);
+       // XXX not working?
+       RNA_boolean_set(WM_keymap_add_item(keymap, "UV_OT_loop_select", SELECTMOUSE, KM_PRESS, KM_SHIFT, KM_ALT)->ptr, "extend", 1);
+
+       WM_keymap_add_item(keymap, "UV_OT_select_linked", LKEY, KM_PRESS, KM_CTRL, 0);
+       WM_keymap_add_item(keymap, "UV_OT_unlink_selection", LKEY, KM_PRESS, KM_ALT, 0);
        WM_keymap_add_item(keymap, "UV_OT_de_select_all", AKEY, KM_PRESS, 0, 0);
        WM_keymap_add_item(keymap, "UV_OT_select_inverse", IKEY, KM_PRESS, KM_CTRL, 0);
 
index 3a40df6..5adcb41 100644 (file)
@@ -840,10 +840,10 @@ typedef struct Scene {
 #define UV_SHOW_SAME_IMAGE     2
 
 /* toolsettings->uv_selectmode */
-#define UV_SELECT_VERTEX       0
-#define UV_SELECT_EDGE         1 /* not implemented */
-#define UV_SELECT_FACE         2
-#define UV_SELECT_ISLAND       3
+#define UV_SELECT_VERTEX       1
+#define UV_SELECT_EDGE         2 /* not implemented */
+#define UV_SELECT_FACE         4
+#define UV_SELECT_ISLAND       8
 
 /* toolsettings->edge_mode */
 #define EDGE_MODE_SELECT                               0
index 4afe8fb..684f133 100644 (file)
@@ -89,7 +89,7 @@
 /***/
 
 /* define for setting colors in theme below */
-#define SETCOL(col, r, g, b, a)  col[0]=r; col[1]=g; col[2]= b; col[3]= a;
+#define SETCOL(col, r, g, b, a)  {col[0]=r; col[1]=g; col[2]= b; col[3]= a;}
 
 /* patching UserDef struct and Themes */
 static void init_userdef_themes(void)
@@ -337,6 +337,18 @@ static void init_userdef_themes(void)
                /* adjust default interpolation for new IPO-curves */
                U.ipo_new= BEZT_IPO_BEZ;
        }
+       if (G.main->versionfile < 250) {
+               bTheme *btheme;
+
+               /* this was not properly initialized in 2.45 */
+               for(btheme= U.themes.first; btheme; btheme= btheme->next) {
+                       if(btheme->tima.face_dot[3]==0) {
+                               SETCOL(btheme->tima.editmesh_active, 255, 255, 255, 128);
+                               SETCOL(btheme->tima.face_dot, 255, 133, 0, 255);
+                               btheme->tima.facedot_size= 2;
+                       }
+               }
+       }
        
        /* GL Texture Garbage Collection (variable abused above!) */
        if (U.textimeout == 0) {