doxygen: blender/editors tagged.
[blender-staging.git] / source / blender / editors / uvedit / uvedit_ops.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /** \file blender/editors/uvedit/uvedit_ops.c
31  *  \ingroup eduv
32  */
33
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <math.h>
38
39 #include "MEM_guardedalloc.h"
40
41 #include "DNA_object_types.h"
42 #include "DNA_meshdata_types.h"
43 #include "DNA_scene_types.h"
44
45 #include "BLI_math.h"
46 #include "BLI_blenlib.h"
47 #include "BLI_editVert.h"
48 #include "BLI_utildefines.h"
49
50 #include "BKE_context.h"
51 #include "BKE_customdata.h"
52 #include "BKE_depsgraph.h"
53 #include "BKE_image.h"
54 #include "BKE_library.h"
55 #include "BKE_mesh.h"
56 #include "BKE_report.h"
57
58 #include "ED_image.h"
59 #include "ED_mesh.h"
60 #include "ED_uvedit.h"
61 #include "ED_object.h"
62 #include "ED_screen.h"
63 #include "ED_transform.h"
64
65 #include "RNA_access.h"
66 #include "RNA_define.h"
67
68 #include "WM_api.h"
69 #include "WM_types.h"
70
71 #include "UI_view2d.h"
72
73 #include "uvedit_intern.h"
74
75 /************************* state testing ************************/
76
77 int ED_uvedit_test(Object *obedit)
78 {
79         EditMesh *em;
80         int ret;
81
82         if(!obedit || obedit->type != OB_MESH)
83                 return 0;
84
85         em = BKE_mesh_get_editmesh(obedit->data);
86         ret = EM_texFaceCheck(em);
87         BKE_mesh_end_editmesh(obedit->data, em);
88         
89         return ret;
90 }
91
92 /************************* assign image ************************/
93
94 void ED_uvedit_assign_image(Scene *scene, Object *obedit, Image *ima, Image *previma)
95 {
96         EditMesh *em;
97         EditFace *efa;
98         MTFace *tf;
99         int update= 0;
100         
101         /* skip assigning these procedural images... */
102         if(ima && (ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE))
103                 return;
104
105         /* verify we have a mesh we can work with */
106         if(!obedit || (obedit->type != OB_MESH))
107                 return;
108
109         em= BKE_mesh_get_editmesh(((Mesh*)obedit->data));
110         if(!em || !em->faces.first) {
111                 BKE_mesh_end_editmesh(obedit->data, em);
112                 return;
113         }
114         
115         /* ensure we have a uv layer */
116         if(!CustomData_has_layer(&em->fdata, CD_MTFACE)) {
117                 EM_add_data_layer(em, &em->fdata, CD_MTFACE, NULL);
118                 update= 1;
119         }
120
121         /* now assign to all visible faces */
122         for(efa= em->faces.first; efa; efa= efa->next) {
123                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
124
125                 if(uvedit_face_visible(scene, previma, efa, tf)) {
126                         if(ima) {
127                                 tf->tpage= ima;
128                                 tf->mode |= TF_TEX;
129                                 
130                                 if(ima->id.us==0) id_us_plus(&ima->id);
131                                 else id_lib_extern(&ima->id);
132                         }
133                         else {
134                                 tf->tpage= NULL;
135                                 tf->mode &= ~TF_TEX;
136                         }
137
138                         update = 1;
139                 }
140         }
141
142         /* and update depdency graph */
143         if(update)
144                 DAG_id_tag_update(obedit->data, 0);
145
146         BKE_mesh_end_editmesh(obedit->data, em);
147 }
148
149 /* dotile -     1, set the tile flag (from the space image)
150  *                      2, set the tile index for the faces. */
151 static int uvedit_set_tile(Object *obedit, Image *ima, int curtile)
152 {
153         EditMesh *em;
154         EditFace *efa;
155         MTFace *tf;
156         
157         /* verify if we have something to do */
158         if(!ima || !ED_uvedit_test(obedit))
159                 return 0;
160
161         if((ima->tpageflag & IMA_TILES) == 0)
162                 return 0;
163
164         /* skip assigning these procedural images... */
165         if(ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE)
166                 return 0;
167         
168         em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
169
170         for(efa= em->faces.first; efa; efa= efa->next) {
171                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
172
173                 if(efa->h==0 && efa->f & SELECT)
174                         tf->tile= curtile; /* set tile index */
175         }
176
177         DAG_id_tag_update(obedit->data, 0);
178         BKE_mesh_end_editmesh(obedit->data, em);
179
180         return 1;
181 }
182
183 /*********************** space conversion *********************/
184
185 static void uvedit_pixel_to_float(SpaceImage *sima, float *dist, float pixeldist)
186 {
187         int width, height;
188
189         if(sima) {
190                 ED_space_image_size(sima, &width, &height);
191         }
192         else {
193                 width= 256;
194                 height= 256;
195         }
196
197         dist[0]= pixeldist/width;
198         dist[1]= pixeldist/height;
199 }
200
201 /*************** visibility and selection utilities **************/
202
203 int uvedit_face_visible_nolocal(Scene *scene, EditFace *efa)
204 {
205         ToolSettings *ts= scene->toolsettings;
206
207         if(ts->uv_flag & UV_SYNC_SELECTION)
208                 return (efa->h==0);
209         else
210                 return (efa->h==0 && (efa->f & SELECT));
211 }
212
213 int uvedit_face_visible(Scene *scene, Image *ima, EditFace *efa, MTFace *tf)
214 {
215         ToolSettings *ts= scene->toolsettings;
216
217         if(ts->uv_flag & UV_SHOW_SAME_IMAGE)
218                 return (tf->tpage==ima)? uvedit_face_visible_nolocal(scene, efa): 0;
219         else
220                 return uvedit_face_visible_nolocal(scene, efa);
221 }
222
223 int uvedit_face_selected(Scene *scene, EditFace *efa, MTFace *tf)
224 {
225         ToolSettings *ts= scene->toolsettings;
226
227         if(ts->uv_flag & UV_SYNC_SELECTION)
228                 return (efa->f & SELECT);
229         else
230                 return (!(~tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) &&(!efa->v4 || tf->flag & TF_SEL4));
231 }
232
233 void uvedit_face_select(Scene *scene, EditFace *efa, MTFace *tf)
234 {
235         ToolSettings *ts= scene->toolsettings;
236
237         if(ts->uv_flag & UV_SYNC_SELECTION)
238                 EM_select_face(efa, 1);
239         else
240                 tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
241 }
242
243 void uvedit_face_deselect(Scene *scene, EditFace *efa, MTFace *tf)
244 {
245         ToolSettings *ts= scene->toolsettings;
246
247         if(ts->uv_flag & UV_SYNC_SELECTION)
248                 EM_select_face(efa, 0);
249         else
250                 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
251 }
252
253 int uvedit_edge_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
254 {
255         ToolSettings *ts= scene->toolsettings;
256         int nvert= (efa->v4)? 4: 3;
257
258         if(ts->uv_flag & UV_SYNC_SELECTION) {
259                 if(ts->selectmode & SCE_SELECT_FACE)
260                         return (efa->f & SELECT);
261                 else if(ts->selectmode & SCE_SELECT_EDGE)
262                         return (*(&efa->e1 + i))->f & SELECT;
263                 else
264                         return (((efa->v1 + i)->f & SELECT) && ((efa->v1 + (i+1)%nvert)->f & SELECT));
265         }
266         else
267                 return (tf->flag & TF_SEL_MASK(i)) && (tf->flag & TF_SEL_MASK((i+1)%nvert));
268 }
269
270 void uvedit_edge_select(Scene *scene, EditFace *efa, MTFace *tf, int i)
271 {
272         ToolSettings *ts= scene->toolsettings;
273         int nvert= (efa->v4)? 4: 3;
274
275         if(ts->uv_flag & UV_SYNC_SELECTION) {
276                 if(ts->selectmode & SCE_SELECT_FACE)
277                         EM_select_face(efa, 1);
278                 else if(ts->selectmode & SCE_SELECT_EDGE)
279                         EM_select_edge((*(&efa->e1 + i)), 1);
280                 else {
281                         (efa->v1 + i)->f |= SELECT;
282                         (efa->v1 + (i+1)%nvert)->f |= SELECT;
283                 }
284         }
285         else
286                 tf->flag |= TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert);
287 }
288
289 void uvedit_edge_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i)
290 {
291         ToolSettings *ts= scene->toolsettings;
292         int nvert= (efa->v4)? 4: 3;
293
294         if(ts->uv_flag & UV_SYNC_SELECTION) {
295                 if(ts->selectmode & SCE_SELECT_FACE)
296                         EM_select_face(efa, 0);
297                 else if(ts->selectmode & SCE_SELECT_EDGE)
298                         EM_select_edge((*(&efa->e1 + i)), 0);
299                 else {
300                         (efa->v1 + i)->f &= ~SELECT;
301                         (efa->v1 + (i+1)%nvert)->f &= ~SELECT;
302                 }
303         }
304         else
305                 tf->flag &= ~(TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert));
306 }
307
308 int uvedit_uv_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
309 {
310         ToolSettings *ts= scene->toolsettings;
311
312         if(ts->uv_flag & UV_SYNC_SELECTION) {
313                 if(ts->selectmode & SCE_SELECT_FACE)
314                         return (efa->f & SELECT);
315                 else
316                         return (*(&efa->v1 + i))->f & SELECT;
317         }
318         else
319                 return tf->flag & TF_SEL_MASK(i);
320 }
321
322 void uvedit_uv_select(Scene *scene, EditFace *efa, MTFace *tf, int i)
323 {
324         ToolSettings *ts= scene->toolsettings;
325
326         if(ts->uv_flag & UV_SYNC_SELECTION) {
327                 if(ts->selectmode & SCE_SELECT_FACE)
328                         EM_select_face(efa, 1);
329                 else
330                         (*(&efa->v1 + i))->f |= SELECT;
331         }
332         else
333                 tf->flag |= TF_SEL_MASK(i);
334 }
335
336 void uvedit_uv_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i)
337 {
338         ToolSettings *ts= scene->toolsettings;
339
340         if(ts->uv_flag & UV_SYNC_SELECTION) {
341                 if(ts->selectmode & SCE_SELECT_FACE)
342                         EM_select_face(efa, 0);
343                 else
344                         (*(&efa->v1 + i))->f &= ~SELECT;
345         }
346         else
347                 tf->flag &= ~TF_SEL_MASK(i);
348 }
349
350 /*********************** geometric utilities ***********************/
351
352 void uv_center(float uv[][2], float cent[2], int quad)
353 {
354         if(quad) {
355                 cent[0] = (uv[0][0] + uv[1][0] + uv[2][0] + uv[3][0]) / 4.0;
356                 cent[1] = (uv[0][1] + uv[1][1] + uv[2][1] + uv[3][1]) / 4.0;            
357         }
358         else {
359                 cent[0] = (uv[0][0] + uv[1][0] + uv[2][0]) / 3.0;
360                 cent[1] = (uv[0][1] + uv[1][1] + uv[2][1]) / 3.0;               
361         }
362 }
363
364 float uv_area(float uv[][2], int quad)
365 {
366         if(quad)
367                 return area_tri_v2(uv[0], uv[1], uv[2]) + area_tri_v2(uv[0], uv[2], uv[3]); 
368         else
369                 return area_tri_v2(uv[0], uv[1], uv[2]); 
370 }
371
372 void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy)
373 {
374         uv[0][0] = uv_orig[0][0]*aspx;
375         uv[0][1] = uv_orig[0][1]*aspy;
376         
377         uv[1][0] = uv_orig[1][0]*aspx;
378         uv[1][1] = uv_orig[1][1]*aspy;
379         
380         uv[2][0] = uv_orig[2][0]*aspx;
381         uv[2][1] = uv_orig[2][1]*aspy;
382         
383         uv[3][0] = uv_orig[3][0]*aspx;
384         uv[3][1] = uv_orig[3][1]*aspy;
385 }
386
387 int ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float *min, float *max)
388 {
389         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
390         EditFace *efa;
391         MTFace *tf;
392         int sel;
393
394         INIT_MINMAX2(min, max);
395
396         sel= 0;
397         for(efa= em->faces.first; efa; efa= efa->next) {
398                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
399                 if(uvedit_face_visible(scene, ima, efa, tf)) {
400                         if(uvedit_uv_selected(scene, efa, tf, 0))                               { DO_MINMAX2(tf->uv[0], min, max); sel = 1; }
401                         if(uvedit_uv_selected(scene, efa, tf, 1))                               { DO_MINMAX2(tf->uv[1], min, max); sel = 1; }
402                         if(uvedit_uv_selected(scene, efa, tf, 2))                               { DO_MINMAX2(tf->uv[2], min, max); sel = 1; }
403                         if(efa->v4 && (uvedit_uv_selected(scene, efa, tf, 3)))  { DO_MINMAX2(tf->uv[3], min, max); sel = 1; }
404                 }
405         }
406         
407         BKE_mesh_end_editmesh(obedit->data, em);
408         return sel;
409 }
410
411 static int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent, int mode)
412 {
413         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
414         EditFace *efa;
415         MTFace *tf;
416         float min[2], max[2];
417         int change= 0;
418         
419         if(mode==0) {
420                 if(ED_uvedit_minmax(scene, ima, obedit, min, max))
421                         change = 1;
422         }
423         else if(mode==1) {
424                 INIT_MINMAX2(min, max);
425                 
426                 for(efa= em->faces.first; efa; efa= efa->next) {
427                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
428
429                         if(uvedit_face_visible(scene, ima, efa, tf)) {
430                                 if(uvedit_uv_selected(scene, efa, tf, 0))                               { DO_MINMAX2(tf->uv[0], min, max);      change= 1;}
431                                 if(uvedit_uv_selected(scene, efa, tf, 1))                               { DO_MINMAX2(tf->uv[1], min, max);      change= 1;}
432                                 if(uvedit_uv_selected(scene, efa, tf, 2))                               { DO_MINMAX2(tf->uv[2], min, max);      change= 1;}
433                                 if(efa->v4 && (uvedit_uv_selected(scene, efa, tf, 3)))  { DO_MINMAX2(tf->uv[3], min, max);      change= 1;}
434                         }
435                 }
436         }
437         
438         if(change) {
439                 cent[0]= (min[0]+max[0])/2.0;
440                 cent[1]= (min[1]+max[1])/2.0;
441                 
442                 BKE_mesh_end_editmesh(obedit->data, em);
443                 return 1;
444         }
445
446         BKE_mesh_end_editmesh(obedit->data, em);
447         return 0;
448 }
449
450 /************************** find nearest ****************************/
451
452 typedef struct NearestHit {
453         EditFace *efa;
454         MTFace *tf;
455
456         int vert, uv;
457         int edge, vert2;
458 } NearestHit;
459
460 static void find_nearest_uv_edge(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
461 {
462         MTFace *tf;
463         EditFace *efa;
464         EditVert *eve;
465         float mindist, dist;
466         int i, nverts;
467
468         mindist= 1e10f;
469         memset(hit, 0, sizeof(*hit));
470
471         for(i=0, eve=em->verts.first; eve; eve=eve->next, i++)
472                 eve->tmp.l = i;
473         
474         for(efa= em->faces.first; efa; efa= efa->next) {
475                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
476
477                 if(uvedit_face_visible(scene, ima, efa, tf)) {
478                         nverts= efa->v4? 4: 3;
479
480                         for(i=0; i<nverts; i++) {
481                                 dist= dist_to_line_segment_v2(co, tf->uv[i], tf->uv[(i+1)%nverts]);
482
483                                 if(dist < mindist) {
484                                         hit->tf= tf;
485                                         hit->efa= efa;
486                                         hit->edge= i;
487                                         mindist= dist;
488
489                                         hit->vert= (*(&efa->v1 + i))->tmp.l;
490                                         hit->vert2= (*(&efa->v1 + ((i+1)%nverts)))->tmp.l;
491                                 }
492                         }
493                 }
494         }
495 }
496
497 static void find_nearest_uv_face(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
498 {
499         MTFace *tf;
500         EditFace *efa;
501         float mindist, dist, cent[2];
502         int i, nverts;
503
504         mindist= 1e10f;
505         memset(hit, 0, sizeof(*hit));
506         
507         for(efa= em->faces.first; efa; efa= efa->next) {
508                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
509
510                 if(uvedit_face_visible(scene, ima, efa, tf)) {
511                         nverts= efa->v4? 4: 3;
512                         cent[0]= cent[1]= 0.0f;
513
514                         for(i=0; i<nverts; i++) {
515                                 cent[0] += tf->uv[i][0];
516                                 cent[1] += tf->uv[i][1];
517                         }
518
519                         cent[0] /= nverts;
520                         cent[1] /= nverts;
521                         dist= fabs(co[0]- cent[0]) + fabs(co[1]- cent[1]);
522
523                         if(dist < mindist) {
524                                 hit->tf= tf;
525                                 hit->efa= efa;
526                                 mindist= dist;
527                         }
528                 }
529         }
530 }
531
532 static int nearest_uv_between(MTFace *tf, int nverts, int id, float co[2], float uv[2])
533 {
534         float m[3], v1[3], v2[3], c1, c2;
535         int id1, id2;
536
537         id1= (id+nverts-1)%nverts;
538         id2= (id+nverts+1)%nverts;
539
540         m[0]= co[0]-uv[0];
541         m[1]= co[1]-uv[1];
542         sub_v2_v2v2(v1, tf->uv[id1], tf->uv[id]);
543         sub_v2_v2v2(v2, tf->uv[id2], tf->uv[id]);
544
545         /* m and v2 on same side of v-v1? */
546         c1= v1[0]*m[1] - v1[1]*m[0];
547         c2= v1[0]*v2[1] - v1[1]*v2[0];
548
549         if(c1*c2 < 0.0f)
550                 return 0;
551
552         /* m and v1 on same side of v-v2? */
553         c1= v2[0]*m[1] - v2[1]*m[0];
554         c2= v2[0]*v1[1] - v2[1]*v1[0];
555
556         return (c1*c2 >= 0.0f);
557 }
558
559 static void find_nearest_uv_vert(Scene *scene, Image *ima, EditMesh *em, float co[2], float penalty[2], NearestHit *hit)
560 {
561         EditFace *efa;
562         EditVert *eve;
563         MTFace *tf;
564         float mindist, dist;
565         int i, nverts;
566
567         mindist= 1e10f;
568         memset(hit, 0, sizeof(*hit));
569         
570         for(i=0, eve=em->verts.first; eve; eve=eve->next, i++)
571                 eve->tmp.l = i;
572         
573         for(efa= em->faces.first; efa; efa= efa->next) {
574                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
575
576                 if(uvedit_face_visible(scene, ima, efa, tf)) {
577                         nverts= efa->v4? 4: 3;
578
579                         for(i=0; i<nverts; i++) {
580                                 if(penalty && uvedit_uv_selected(scene, efa, tf, i))
581                                         dist= fabs(co[0]-tf->uv[i][0])+penalty[0] + fabs(co[1]-tf->uv[i][1])+penalty[1];
582                                 else
583                                         dist= fabs(co[0]-tf->uv[i][0]) + fabs(co[1]-tf->uv[i][1]);
584
585                                 if(dist<=mindist) {
586                                         if(dist==mindist)
587                                                 if(!nearest_uv_between(tf, nverts, i, co, tf->uv[i]))
588                                                         continue;
589
590                                         mindist= dist;
591
592                                         hit->uv= i;
593                                         hit->tf= tf;
594                                         hit->efa= efa;
595
596                                         hit->vert= (*(&efa->v1 + i))->tmp.l;
597                                 }
598                         }
599                 }
600         }
601 }
602
603 int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, float co[2], float uv[2])
604 {
605         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
606         EditFace *efa;
607         MTFace *tf;
608         float mindist, dist;
609         int i, nverts, found= 0;
610
611         mindist= 1e10f;
612         uv[0]= co[0];
613         uv[1]= co[1];
614         
615         for(efa= em->faces.first; efa; efa= efa->next) {
616                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
617
618                 if(uvedit_face_visible(scene, ima, efa, tf)) {
619                         nverts= efa->v4? 4: 3;
620
621                         for(i=0; i<nverts; i++) {
622                                 dist= fabs(co[0]-tf->uv[i][0]) + fabs(co[1]-tf->uv[i][1]);
623
624                                 if(dist<=mindist) {
625                                         mindist= dist;
626
627                                         uv[0]= tf->uv[i][0];
628                                         uv[1]= tf->uv[i][1];
629                                         found= 1;
630                                 }
631                         }
632                 }
633         }
634
635         BKE_mesh_end_editmesh(obedit->data, em);
636         return found;
637 }
638
639 /*********************** loop select ***********************/
640
641 static void uv_vertex_loop_flag(UvMapVert *first)
642 {
643         UvMapVert *iterv;
644         int count= 0;
645
646         for(iterv=first; iterv; iterv=iterv->next) {
647                 if(iterv->separate && iterv!=first)
648                         break;
649
650                 count++;
651         }
652         
653         if(count < 5)
654                 first->flag= 1;
655 }
656
657 static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, EditFace *efa, int a)
658 {
659         UvMapVert *iterv, *first;
660         
661         first= EM_get_uv_map_vert(vmap, (*(&efa->v1 + a))->tmp.l);
662
663         for(iterv=first; iterv; iterv=iterv->next) {
664                 if(iterv->separate)
665                         first= iterv;
666                 if(iterv->f == efa->tmp.l)
667                         return first;
668         }
669         
670         return NULL;
671 }
672
673 static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface)
674 {
675         UvMapVert *iterv1, *iterv2;
676         EditFace *efa;
677         int tot = 0;
678
679         /* count number of faces this edge has */
680         for(iterv1=first1; iterv1; iterv1=iterv1->next) {
681                 if(iterv1->separate && iterv1 != first1)
682                         break;
683
684                 for(iterv2=first2; iterv2; iterv2=iterv2->next) {
685                         if(iterv2->separate && iterv2 != first2)
686                                 break;
687
688                         if(iterv1->f == iterv2->f) {
689                                 /* if face already tagged, don't do this edge */
690                                 efa= EM_get_face_for_index(iterv1->f);
691                                 if(efa->f1)
692                                         return 0;
693
694                                 tot++;
695                                 break;
696                         }
697                 }
698         }
699
700         if(*totface == 0) /* start edge */
701                 *totface= tot;
702         else if(tot != *totface) /* check for same number of faces as start edge */
703                 return 0;
704
705         /* tag the faces */
706         for(iterv1=first1; iterv1; iterv1=iterv1->next) {
707                 if(iterv1->separate && iterv1 != first1)
708                         break;
709
710                 for(iterv2=first2; iterv2; iterv2=iterv2->next) {
711                         if(iterv2->separate && iterv2 != first2)
712                                 break;
713
714                         if(iterv1->f == iterv2->f) {
715                                 efa= EM_get_face_for_index(iterv1->f);
716                                 efa->f1= 1;
717                                 break;
718                         }
719                 }
720         }
721
722         return 1;
723 }
724
725 static int select_edgeloop(Scene *scene, Image *ima, EditMesh *em, NearestHit *hit, float limit[2], int extend)
726 {
727         EditVert *eve;
728         EditFace *efa;
729         MTFace *tf;
730         UvVertMap *vmap;
731         UvMapVert *iterv1, *iterv2;
732         int a, count, looking, nverts, starttotf, select;
733
734         /* setup */
735         EM_init_index_arrays(em, 0, 0, 1);
736         vmap= EM_make_uv_vert_map(em, 0, 0, limit);
737
738         for(count=0, eve=em->verts.first; eve; count++, eve= eve->next)
739                 eve->tmp.l = count;
740
741         for(count=0, efa= em->faces.first; efa; count++, efa= efa->next) {
742                 if(!extend) {
743                         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
744                         uvedit_face_deselect(scene, efa, tf);
745                 }
746
747                 efa->tmp.l= count;
748                 efa->f1= 0;
749         }
750         
751         /* set flags for first face and verts */
752         nverts= (hit->efa->v4)? 4: 3;
753         iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge);
754         iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts);
755         uv_vertex_loop_flag(iterv1);
756         uv_vertex_loop_flag(iterv2);
757
758         starttotf= 0;
759         uv_edge_tag_faces(iterv1, iterv2, &starttotf);
760
761         /* sorry, first edge isnt even ok */
762         if(iterv1->flag==0 && iterv2->flag==0) looking= 0;
763         else looking= 1;
764
765         /* iterate */
766         while(looking) {
767                 looking= 0;
768
769                 /* find correct valence edges which are not tagged yet, but connect to tagged one */
770                 for(efa= em->faces.first; efa; efa=efa->next) {
771                         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
772
773                         if(!efa->f1 && uvedit_face_visible(scene, ima, efa, tf)) {
774                                 nverts= (efa->v4)? 4: 3;
775                                 for(a=0; a<nverts; a++) {
776                                         /* check face not hidden and not tagged */
777                                         iterv1= uv_vertex_map_get(vmap, efa, a);
778                                         iterv2= uv_vertex_map_get(vmap, efa, (a+1)%nverts);
779
780                                         /* check if vertex is tagged and has right valence */
781                                         if(iterv1->flag || iterv2->flag) {
782                                                 if(uv_edge_tag_faces(iterv1, iterv2, &starttotf)) {
783                                                         looking= 1;
784                                                         efa->f1= 1;
785
786                                                         uv_vertex_loop_flag(iterv1);
787                                                         uv_vertex_loop_flag(iterv2);
788                                                         break;
789                                                 }
790                                         }
791                                 }
792                         }
793                 }
794         }
795
796         /* do the actual select/deselect */
797         nverts= (hit->efa->v4)? 4: 3;
798         iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge);
799         iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts);
800         iterv1->flag= 1;
801         iterv2->flag= 1;
802
803         if(extend) {
804                 tf= CustomData_em_get(&em->fdata, hit->efa->data, CD_MTFACE);
805
806                 if(uvedit_uv_selected(scene, hit->efa, tf, hit->edge) && uvedit_uv_selected(scene, hit->efa, tf, hit->edge))
807                         select= 0;
808                 else
809                         select= 1;
810         }
811         else
812                 select= 1;
813         
814         for(efa= em->faces.first; efa; efa=efa->next) {
815                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
816
817                 nverts= (efa->v4)? 4: 3;
818                 for(a=0; a<nverts; a++) {
819                         iterv1= uv_vertex_map_get(vmap, efa, a);
820
821                         if(iterv1->flag) {
822                                 if(select) uvedit_uv_select(scene, efa, tf, a);
823                                 else uvedit_uv_deselect(scene, efa, tf, a);
824                         }
825                 }
826         }
827
828         /* cleanup */
829         EM_free_uv_vert_map(vmap);
830         EM_free_index_arrays();
831
832         return (select)? 1: -1;
833 }
834
835 /*********************** linked select ***********************/
836
837 static void select_linked(Scene *scene, Image *ima, EditMesh *em, float limit[2], NearestHit *hit, int extend)
838 {
839         EditFace *efa;
840         MTFace *tf;
841         UvVertMap *vmap;
842         UvMapVert *vlist, *iterv, *startv;
843         int i, nverts, stacksize= 0, *stack;
844         unsigned int a;
845         char *flag;
846
847         EM_init_index_arrays(em, 0, 0, 1); /* we can use this too */
848         vmap= EM_make_uv_vert_map(em, 1, 0, limit);
849         if(vmap == NULL)
850                 return;
851
852         stack= MEM_mallocN(sizeof(*stack) * em->totface, "UvLinkStack");
853         flag= MEM_callocN(sizeof(*flag) * em->totface, "UvLinkFlag");
854
855         if(!hit) {
856                 for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
857                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
858
859                         if(uvedit_face_visible(scene, ima, efa, tf)) {
860                                 const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
861                                 if(tf->flag & select_flag) {
862                                         stack[stacksize]= a;
863                                         stacksize++;
864                                         flag[a]= 1;
865                                 }
866                         }
867                 }
868         }
869         else {
870                 for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
871                         if(efa == hit->efa) {
872                                 stack[stacksize]= a;
873                                 stacksize++;
874                                 flag[a]= 1;
875                                 break;
876                         }
877                 }
878         }
879
880         while(stacksize > 0) {
881                 stacksize--;
882                 a= stack[stacksize];
883
884                 efa = EM_get_face_for_index(a);
885
886                 nverts= efa->v4? 4: 3;
887
888                 for(i=0; i<nverts; i++) {
889                         /* make_uv_vert_map_EM sets verts tmp.l to the indices */
890                         vlist= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l);
891                         
892                         startv= vlist;
893
894                         for(iterv=vlist; iterv; iterv=iterv->next) {
895                                 if(iterv->separate)
896                                         startv= iterv;
897                                 if(iterv->f == a)
898                                         break;
899                         }
900
901                         for(iterv=startv; iterv; iterv=iterv->next) {
902                                 if((startv != iterv) && (iterv->separate))
903                                         break;
904                                 else if(!flag[iterv->f]) {
905                                         flag[iterv->f]= 1;
906                                         stack[stacksize]= iterv->f;
907                                         stacksize++;
908                                 }
909                         }
910                 }
911         }
912
913         if(!extend) {
914                 for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
915                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
916                         if(flag[a])
917                                 tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
918                         else
919                                 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
920                 }
921         }
922         else {
923                 for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
924                         if(flag[a]) {
925                                 const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
926                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
927                                 if((tf->flag & select_flag))
928                                         break;
929                         }
930                 }
931
932                 if(efa) {
933                         for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
934                                 if(flag[a]) {
935                                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
936                                         tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
937                                 }
938                         }
939                 }
940                 else {
941                         for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
942                                 if(flag[a]) {
943                                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
944                                         tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
945                                 }
946                         }
947                 }
948         }
949         
950         MEM_freeN(stack);
951         MEM_freeN(flag);
952         EM_free_uv_vert_map(vmap);
953         EM_free_index_arrays();
954 }
955
956 /* ******************** align operator **************** */
957
958 static void weld_align_uv(bContext *C, int tool)
959 {
960         Scene *scene;
961         Object *obedit;
962         Image *ima;
963         EditMesh *em;
964         EditFace *efa;
965         MTFace *tf;
966         float cent[2], min[2], max[2];
967         
968         scene= CTX_data_scene(C);
969         obedit= CTX_data_edit_object(C);
970         em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
971         ima= CTX_data_edit_image(C);
972
973         INIT_MINMAX2(min, max);
974
975         if(tool == 'a') {
976                 for(efa= em->faces.first; efa; efa= efa->next) {
977                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
978
979                         if(uvedit_face_visible(scene, ima, efa, tf)) {
980                                 if(uvedit_uv_selected(scene, efa, tf, 0))
981                                         DO_MINMAX2(tf->uv[0], min, max)
982                                 if(uvedit_uv_selected(scene, efa, tf, 1))
983                                         DO_MINMAX2(tf->uv[1], min, max)
984                                 if(uvedit_uv_selected(scene, efa, tf, 2))
985                                         DO_MINMAX2(tf->uv[2], min, max)
986                                 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
987                                         DO_MINMAX2(tf->uv[3], min, max)
988                         }
989                 }
990
991                 tool= (max[0]-min[0] >= max[1]-min[1])? 'y': 'x';
992         }
993
994         uvedit_center(scene, ima, obedit, cent, 0);
995
996         if(tool == 'x' || tool == 'w') {
997                 for(efa= em->faces.first; efa; efa= efa->next) {
998                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
999                         if(uvedit_face_visible(scene, ima, efa, tf)) {
1000                                 if(uvedit_uv_selected(scene, efa, tf, 0))
1001                                         tf->uv[0][0]= cent[0];
1002                                 if(uvedit_uv_selected(scene, efa, tf, 1))
1003                                         tf->uv[1][0]= cent[0];
1004                                 if(uvedit_uv_selected(scene, efa, tf, 2))
1005                                         tf->uv[2][0]= cent[0];
1006                                 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
1007                                         tf->uv[3][0]= cent[0];
1008                         }
1009                 }
1010         }
1011
1012         if(tool == 'y' || tool == 'w') {
1013                 for(efa= em->faces.first; efa; efa= efa->next) {
1014                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1015                         if(uvedit_face_visible(scene, ima, efa, tf)) {
1016                                 if(uvedit_uv_selected(scene, efa, tf, 0))
1017                                         tf->uv[0][1]= cent[1];
1018                                 if(uvedit_uv_selected(scene, efa, tf, 1))
1019                                         tf->uv[1][1]= cent[1];
1020                                 if(uvedit_uv_selected(scene, efa, tf, 2))
1021                                         tf->uv[2][1]= cent[1];
1022                                 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
1023                                         tf->uv[3][1]= cent[1];
1024                         }
1025                 }
1026         }
1027
1028         DAG_id_tag_update(obedit->data, 0);
1029         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1030
1031         BKE_mesh_end_editmesh(obedit->data, em);
1032 }
1033
1034 static int align_exec(bContext *C, wmOperator *op)
1035 {
1036         weld_align_uv(C, RNA_enum_get(op->ptr, "axis"));
1037
1038         return OPERATOR_FINISHED;
1039 }
1040
1041 static void UV_OT_align(wmOperatorType *ot)
1042 {
1043         static EnumPropertyItem axis_items[] = {
1044                 {'a', "ALIGN_AUTO", 0, "Align Auto", "Automatically choose the axis on which there is most alignment already"},
1045                 {'x', "ALIGN_X", 0, "Align X", "Align UVs on X axis"},
1046                 {'y', "ALIGN_Y", 0, "Align Y", "Align UVs on Y axis"},
1047                 {0, NULL, 0, NULL, NULL}};
1048
1049         /* identifiers */
1050         ot->name= "Align";
1051         ot->description= "Align selected UV vertices to an axis";
1052         ot->idname= "UV_OT_align";
1053         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1054         
1055         /* api callbacks */
1056         ot->exec= align_exec;
1057         ot->poll= ED_operator_uvedit;
1058
1059         /* properties */
1060         RNA_def_enum(ot->srna, "axis", axis_items, 'a', "Axis", "Axis to align UV locations on.");
1061 }
1062
1063 /* ******************** weld operator **************** */
1064
1065 static int weld_exec(bContext *C, wmOperator *UNUSED(op))
1066 {
1067         weld_align_uv(C, 'w');
1068
1069         return OPERATOR_FINISHED;
1070 }
1071
1072 static void UV_OT_weld(wmOperatorType *ot)
1073 {
1074         /* identifiers */
1075         ot->name= "Weld";
1076         ot->description= "Weld selected UV vertices together";
1077         ot->idname= "UV_OT_weld";
1078         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1079         
1080         /* api callbacks */
1081         ot->exec= weld_exec;
1082         ot->poll= ED_operator_uvedit;
1083 }
1084
1085 /* ******************** stitch operator **************** */
1086
1087 /* just for averaging UVs */
1088 typedef struct UVVertAverage {
1089         float uv[2];
1090         int count;
1091 } UVVertAverage;
1092
1093 static int stitch_exec(bContext *C, wmOperator *op)
1094 {
1095         Scene *scene;
1096         Object *obedit;
1097         EditMesh *em;
1098         EditFace *efa;
1099         EditVert *eve;
1100         Image *ima;
1101         MTFace *tf;
1102
1103         scene= CTX_data_scene(C);
1104         obedit= CTX_data_edit_object(C);
1105         em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
1106         ima= CTX_data_edit_image(C);
1107         
1108         if(RNA_boolean_get(op->ptr, "use_limit")) {
1109                 UvVertMap *vmap;
1110                 UvMapVert *vlist, *iterv;
1111                 float newuv[2], limit[2];
1112                 int a, vtot;
1113
1114                 limit[0]= RNA_float_get(op->ptr, "limit");
1115                 limit[1]= limit[0];
1116
1117                 EM_init_index_arrays(em, 0, 0, 1);
1118                 vmap= EM_make_uv_vert_map(em, 1, 0, limit);
1119
1120                 if(vmap == NULL) {
1121                         BKE_mesh_end_editmesh(obedit->data, em);
1122                         return OPERATOR_CANCELLED;
1123                 }
1124
1125                 for(a=0, eve= em->verts.first; eve; a++, eve= eve->next) {
1126                         vlist= EM_get_uv_map_vert(vmap, a);
1127
1128                         while(vlist) {
1129                                 newuv[0]= 0; newuv[1]= 0;
1130                                 vtot= 0;
1131
1132                                 for(iterv=vlist; iterv; iterv=iterv->next) {
1133                                         if((iterv != vlist) && iterv->separate)
1134                                                 break;
1135
1136                                         efa = EM_get_face_for_index(iterv->f);
1137                                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1138                                         
1139                                         if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) {
1140                                                 newuv[0] += tf->uv[iterv->tfindex][0];
1141                                                 newuv[1] += tf->uv[iterv->tfindex][1];
1142                                                 vtot++;
1143                                         }
1144                                 }
1145
1146                                 if(vtot > 1) {
1147                                         newuv[0] /= vtot; newuv[1] /= vtot;
1148
1149                                         for(iterv=vlist; iterv; iterv=iterv->next) {
1150                                                 if((iterv != vlist) && iterv->separate)
1151                                                         break;
1152
1153                                                 efa = EM_get_face_for_index(iterv->f);
1154                                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1155
1156                                                 if(uvedit_uv_selected(scene, efa, tf, iterv->tfindex)) {
1157                                                         tf->uv[iterv->tfindex][0]= newuv[0];
1158                                                         tf->uv[iterv->tfindex][1]= newuv[1];
1159                                                 }
1160                                         }
1161                                 }
1162
1163                                 vlist= iterv;
1164                         }
1165                 }
1166
1167                 EM_free_uv_vert_map(vmap);
1168                 EM_free_index_arrays();
1169         }
1170         else {
1171                 UVVertAverage *uv_average, *uvav;
1172                 int count;
1173
1174                 // index and count verts
1175                 for(count=0, eve=em->verts.first; eve; count++, eve= eve->next)
1176                         eve->tmp.l = count;
1177                 
1178                 uv_average= MEM_callocN(sizeof(UVVertAverage)*count, "Stitch");
1179                 
1180                 // gather uv averages per vert
1181                 for(efa= em->faces.first; efa; efa= efa->next) {
1182                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1183
1184                         if(uvedit_face_visible(scene, ima, efa, tf)) {
1185                                 if(uvedit_uv_selected(scene, efa, tf, 0)) {
1186                                         uvav = uv_average + efa->v1->tmp.l;
1187                                         uvav->count++;
1188                                         uvav->uv[0] += tf->uv[0][0];
1189                                         uvav->uv[1] += tf->uv[0][1];
1190                                 }
1191
1192                                 if(uvedit_uv_selected(scene, efa, tf, 1)) {
1193                                         uvav = uv_average + efa->v2->tmp.l;
1194                                         uvav->count++;
1195                                         uvav->uv[0] += tf->uv[1][0];
1196                                         uvav->uv[1] += tf->uv[1][1];
1197                                 }
1198
1199                                 if(uvedit_uv_selected(scene, efa, tf, 2)) {
1200                                         uvav = uv_average + efa->v3->tmp.l;
1201                                         uvav->count++;
1202                                         uvav->uv[0] += tf->uv[2][0];
1203                                         uvav->uv[1] += tf->uv[2][1];
1204                                 }
1205
1206                                 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
1207                                         uvav = uv_average + efa->v4->tmp.l;
1208                                         uvav->count++;
1209                                         uvav->uv[0] += tf->uv[3][0];
1210                                         uvav->uv[1] += tf->uv[3][1];
1211                                 }
1212                         }
1213                 }
1214                 
1215                 // apply uv welding
1216                 for(efa= em->faces.first; efa; efa= efa->next) {
1217                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1218
1219                         if(uvedit_face_visible(scene, ima, efa, tf)) {
1220                                 if(uvedit_uv_selected(scene, efa, tf, 0)) {
1221                                         uvav = uv_average + efa->v1->tmp.l;
1222                                         tf->uv[0][0] = uvav->uv[0]/uvav->count;
1223                                         tf->uv[0][1] = uvav->uv[1]/uvav->count;
1224                                 }
1225
1226                                 if(uvedit_uv_selected(scene, efa, tf, 1)) {
1227                                         uvav = uv_average + efa->v2->tmp.l;
1228                                         tf->uv[1][0] = uvav->uv[0]/uvav->count;
1229                                         tf->uv[1][1] = uvav->uv[1]/uvav->count;
1230                                 }
1231
1232                                 if(uvedit_uv_selected(scene, efa, tf, 2)) {
1233                                         uvav = uv_average + efa->v3->tmp.l;
1234                                         tf->uv[2][0] = uvav->uv[0]/uvav->count;
1235                                         tf->uv[2][1] = uvav->uv[1]/uvav->count;
1236                                 }
1237
1238                                 if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3)) {
1239                                         uvav = uv_average + efa->v4->tmp.l;
1240                                         tf->uv[3][0] = uvav->uv[0]/uvav->count;
1241                                         tf->uv[3][1] = uvav->uv[1]/uvav->count;
1242                                 }
1243                         }
1244                 }
1245
1246                 MEM_freeN(uv_average);
1247         }
1248
1249         DAG_id_tag_update(obedit->data, 0);
1250         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1251
1252         BKE_mesh_end_editmesh(obedit->data, em);
1253         return OPERATOR_FINISHED;
1254 }
1255
1256 static void UV_OT_stitch(wmOperatorType *ot)
1257 {
1258         /* identifiers */
1259         ot->name= "Stitch";
1260         ot->description= "Stitch selected UV vertices by proximity";
1261         ot->idname= "UV_OT_stitch";
1262         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1263         
1264         /* api callbacks */
1265         ot->exec= stitch_exec;
1266         ot->poll= ED_operator_uvedit;
1267
1268         /* properties */
1269         RNA_def_boolean(ot->srna, "use_limit", 1, "Use Limit", "Stitch UVs within a specified limit distance.");
1270         RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit", "Limit distance in normalized coordinates.", -FLT_MAX, FLT_MAX);
1271 }
1272
1273 /* ******************** (de)select all operator **************** */
1274
1275 static int select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
1276 {
1277         Scene *scene;
1278         ToolSettings *ts;
1279         Object *obedit;
1280         EditMesh *em;
1281         EditFace *efa;
1282         Image *ima;
1283         MTFace *tf;
1284         
1285         scene= CTX_data_scene(C);
1286         ts= CTX_data_tool_settings(C);
1287         obedit= CTX_data_edit_object(C);
1288         em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
1289         ima= CTX_data_edit_image(C);
1290
1291         if(ts->uv_flag & UV_SYNC_SELECTION) {
1292                 EM_select_swap(em);
1293         }
1294         else {
1295                 for(efa= em->faces.first; efa; efa= efa->next) {
1296                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1297
1298                         if(uvedit_face_visible(scene, ima, efa, tf)) {
1299                                 tf->flag ^= TF_SEL1;
1300                                 tf->flag ^= TF_SEL2;
1301                                 tf->flag ^= TF_SEL3;
1302                                 if(efa->v4) tf->flag ^= TF_SEL4;
1303                         }
1304                 }
1305         }
1306
1307         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
1308
1309         BKE_mesh_end_editmesh(obedit->data, em);
1310         return OPERATOR_FINISHED;
1311 }
1312
1313 static void UV_OT_select_inverse(wmOperatorType *ot)
1314 {
1315         /* identifiers */
1316         ot->name= "Select Inverse";
1317         ot->description= "Select inverse of (un)selected UV vertices";
1318         ot->idname= "UV_OT_select_inverse";
1319         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1320         
1321         /* api callbacks */
1322         ot->exec= select_inverse_exec;
1323         ot->poll= ED_operator_uvedit;
1324 }
1325
1326 /* ******************** (de)select all operator **************** */
1327
1328 static int select_all_exec(bContext *C, wmOperator *op)
1329 {
1330         Scene *scene;
1331         ToolSettings *ts;
1332         Object *obedit;
1333         EditMesh *em;
1334         EditFace *efa;
1335         Image *ima;
1336         MTFace *tf;
1337         int action = RNA_enum_get(op->ptr, "action");
1338         
1339         scene= CTX_data_scene(C);
1340         ts= CTX_data_tool_settings(C);
1341         obedit= CTX_data_edit_object(C);
1342         em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
1343         ima= CTX_data_edit_image(C);
1344         
1345         if(ts->uv_flag & UV_SYNC_SELECTION) {
1346                 switch (action) {
1347                 case SEL_TOGGLE:
1348                         EM_toggle_select_all(em);
1349                         break;
1350                 case SEL_SELECT:
1351                         EM_select_all(em);
1352                         break;
1353                 case SEL_DESELECT:
1354                         EM_deselect_all(em);
1355                         break;
1356                 case SEL_INVERT:
1357                         EM_select_swap(em);
1358                         break;
1359                 }
1360         }
1361         else {
1362
1363                 if (action == SEL_TOGGLE) {
1364                         action = SEL_SELECT;
1365                         for(efa= em->faces.first; efa; efa= efa->next) {
1366                                 const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
1367                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1368
1369                                 if(uvedit_face_visible(scene, ima, efa, tf)) {
1370                                         if(tf->flag & select_flag) {
1371                                                 action = SEL_DESELECT;
1372                                                 break;
1373                                         }
1374                                 }
1375                         }
1376                 }
1377         
1378                 for(efa= em->faces.first; efa; efa= efa->next) {
1379                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1380
1381                         if(uvedit_face_visible(scene, ima, efa, tf)) {
1382                                 const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
1383
1384                                 switch (action) {
1385                                 case SEL_SELECT:
1386                                         tf->flag |= select_flag;
1387                                         break;
1388                                 case SEL_DESELECT:
1389                                         tf->flag &= ~select_flag;
1390                                         break;
1391                                 case SEL_INVERT:
1392                                         if ((tf->flag & select_flag) == select_flag) {
1393                                                 tf->flag &= ~select_flag;
1394                                         } else {
1395                                                 tf->flag &= ~select_flag;
1396                                         }
1397                                         break;
1398                                 }
1399                         }
1400                 }
1401         }
1402
1403         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1404
1405         BKE_mesh_end_editmesh(obedit->data, em);
1406         return OPERATOR_FINISHED;
1407 }
1408
1409 static void UV_OT_select_all(wmOperatorType *ot)
1410 {
1411         /* identifiers */
1412         ot->name= "Select or Deselect All";
1413         ot->description= "Change selection of all UV vertices";
1414         ot->idname= "UV_OT_select_all";
1415         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1416         
1417         /* api callbacks */
1418         ot->exec= select_all_exec;
1419         ot->poll= ED_operator_uvedit;
1420
1421         WM_operator_properties_select_all(ot);
1422 }
1423
1424 /* ******************** mouse select operator **************** */
1425
1426 static int sticky_select(float *limit, int hitv[4], int v, float *hituv[4], float *uv, int sticky)
1427 {
1428         int i;
1429
1430         /* this function test if some vertex needs to selected
1431          * in addition to the existing ones due to sticky select */
1432         if(sticky == SI_STICKY_DISABLE)
1433                 return 0;
1434
1435         for(i=0; i<4; i++) {
1436                 if(hitv[i] == v) {
1437                         if(sticky == SI_STICKY_LOC) {
1438                                 if(fabs(hituv[i][0]-uv[0]) < limit[0] && fabs(hituv[i][1]-uv[1]) < limit[1])
1439                                         return 1;
1440                         }
1441                         else if(sticky == SI_STICKY_VERTEX)
1442                                 return 1;
1443                 }
1444         }
1445
1446         return 0;
1447 }
1448
1449 static int mouse_select(bContext *C, float co[2], int extend, int loop)
1450 {
1451         SpaceImage *sima= CTX_wm_space_image(C);
1452         Scene *scene= CTX_data_scene(C);
1453         ToolSettings *ts= CTX_data_tool_settings(C);
1454         Object *obedit= CTX_data_edit_object(C);
1455         Image *ima= CTX_data_edit_image(C);
1456         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
1457         EditFace *efa;
1458         MTFace *tf;
1459         NearestHit hit;
1460         int a, i, select = 1, selectmode, sticky, sync, hitv[4], nvert;
1461         int flush = 0; /* 0 == dont flush, 1 == sel, -1 == desel;  only use when selection sync is enabled */
1462         float limit[2], *hituv[4], penalty[2];
1463         
1464         uvedit_pixel_to_float(sima, limit, 0.05f);
1465         uvedit_pixel_to_float(sima, penalty, 5.0f);
1466
1467         /* retrieve operation mode */
1468         if(ts->uv_flag & UV_SYNC_SELECTION) {
1469                 sync= 1;
1470
1471                 if(ts->selectmode & SCE_SELECT_FACE)
1472                         selectmode= UV_SELECT_FACE;
1473                 else if(ts->selectmode & SCE_SELECT_EDGE)
1474                         selectmode= UV_SELECT_EDGE;
1475                 else
1476                         selectmode= UV_SELECT_VERTEX;
1477
1478                 sticky= SI_STICKY_DISABLE;
1479         }
1480         else {
1481                 sync= 0;
1482                 selectmode= ts->uv_selectmode;
1483                 sticky= (sima)? sima->sticky: 1;
1484         }
1485
1486         /* find nearest element */
1487         if(loop) {
1488                 /* find edge */
1489                 find_nearest_uv_edge(scene, ima, em, co, &hit);
1490                 if(hit.efa == NULL) {
1491                         BKE_mesh_end_editmesh(obedit->data, em);
1492                         return OPERATOR_CANCELLED;
1493                 }
1494         }
1495         else if(selectmode == UV_SELECT_VERTEX) {
1496                 /* find vertex */
1497                 find_nearest_uv_vert(scene, ima, em, co, penalty, &hit);
1498                 if(hit.efa == NULL) {
1499                         BKE_mesh_end_editmesh(obedit->data, em);
1500                         return OPERATOR_CANCELLED;
1501                 }
1502
1503                 /* mark 1 vertex as being hit */
1504                 for(i=0; i<4; i++)
1505                         hitv[i]= 0xFFFFFFFF;
1506
1507                 hitv[hit.uv]= hit.vert;
1508                 hituv[hit.uv]= hit.tf->uv[hit.uv];
1509         }
1510         else if(selectmode == UV_SELECT_EDGE) {
1511                 /* find edge */
1512                 find_nearest_uv_edge(scene, ima, em, co, &hit);
1513                 if(hit.efa == NULL) {
1514                         BKE_mesh_end_editmesh(obedit->data, em);
1515                         return OPERATOR_CANCELLED;
1516                 }
1517
1518                 /* mark 2 edge vertices as being hit */
1519                 for(i=0; i<4; i++)
1520                         hitv[i]= 0xFFFFFFFF;
1521
1522                 nvert= (hit.efa->v4)? 4: 3;
1523
1524                 hitv[hit.edge]= hit.vert;
1525                 hitv[(hit.edge+1)%nvert]= hit.vert2;
1526                 hituv[hit.edge]= hit.tf->uv[hit.edge];
1527                 hituv[(hit.edge+1)%nvert]= hit.tf->uv[(hit.edge+1)%nvert];
1528         }
1529         else if(selectmode == UV_SELECT_FACE) {
1530                 /* find face */
1531                 find_nearest_uv_face(scene, ima, em, co, &hit);
1532                 if(hit.efa == NULL) {
1533                         BKE_mesh_end_editmesh(obedit->data, em);
1534                         return OPERATOR_CANCELLED;
1535                 }
1536                 
1537                 /* make active */
1538                 EM_set_actFace(em, hit.efa);
1539
1540                 /* mark all face vertices as being hit */
1541                 for(i=0; i<4; i++)
1542                         hituv[i]= hit.tf->uv[i];
1543
1544                 hitv[0]= hit.efa->v1->tmp.l;
1545                 hitv[1]= hit.efa->v2->tmp.l;
1546                 hitv[2]= hit.efa->v3->tmp.l;
1547                 
1548                 if(hit.efa->v4) hitv[3]= hit.efa->v4->tmp.l;
1549                 else hitv[3]= 0xFFFFFFFF;
1550         }
1551         else if(selectmode == UV_SELECT_ISLAND) {
1552                 find_nearest_uv_vert(scene, ima, em, co, NULL, &hit);
1553
1554                 if(hit.efa==NULL) {
1555                         BKE_mesh_end_editmesh(obedit->data, em);
1556                         return OPERATOR_CANCELLED;
1557                 }
1558         }
1559         else {
1560                 BKE_mesh_end_editmesh(obedit->data, em);
1561                 return OPERATOR_CANCELLED;
1562         }
1563
1564         /* do selection */
1565         if(loop) {
1566                 flush= select_edgeloop(scene, ima, em, &hit, limit, extend);
1567         }
1568         else if(selectmode == UV_SELECT_ISLAND) {
1569                 select_linked(scene, ima, em, limit, &hit, extend);
1570         }
1571         else if(extend) {
1572                 if(selectmode == UV_SELECT_VERTEX) {
1573                         /* (de)select uv vertex */
1574                         if(uvedit_uv_selected(scene, hit.efa, hit.tf, hit.uv)) {
1575                                 uvedit_uv_deselect(scene, hit.efa, hit.tf, hit.uv);
1576                                 select= 0;
1577                         }
1578                         else {
1579                                 uvedit_uv_select(scene, hit.efa, hit.tf, hit.uv);
1580                                 select= 1;
1581                         }
1582                         flush = 1;
1583                 }
1584                 else if(selectmode == UV_SELECT_EDGE) {
1585                         /* (de)select edge */
1586                         if(uvedit_edge_selected(scene, hit.efa, hit.tf, hit.edge)) {
1587                                 uvedit_edge_deselect(scene, hit.efa, hit.tf, hit.edge);
1588                                 select= 0;
1589                         }
1590                         else {
1591                                 uvedit_edge_select(scene, hit.efa, hit.tf, hit.edge);
1592                                 select= 1;
1593                         }
1594                         flush = 1;
1595                 }
1596                 else if(selectmode == UV_SELECT_FACE) {
1597                         /* (de)select face */
1598                         if(uvedit_face_selected(scene, hit.efa, hit.tf)) {
1599                                 uvedit_face_deselect(scene, hit.efa, hit.tf);
1600                                 select= 0;
1601                         }
1602                         else {
1603                                 uvedit_face_select(scene, hit.efa, hit.tf);
1604                                 select= 1;
1605                         }
1606                         flush = -1;
1607                 }
1608
1609                 /* (de)select sticky uv nodes */
1610                 if(sticky != SI_STICKY_DISABLE) {
1611                         EditVert *ev;
1612                         
1613                         for(a=0, ev=em->verts.first; ev; ev = ev->next, a++)
1614                                 ev->tmp.l = a;
1615                         
1616                         /* deselect */
1617                         if(select==0) {
1618                                 for(efa= em->faces.first; efa; efa= efa->next) {
1619                                         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1620
1621                                         if(uvedit_face_visible(scene, ima, efa, tf)) {
1622                                                 if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
1623                                                         uvedit_uv_deselect(scene, efa, tf, 0);
1624                                                 if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
1625                                                         uvedit_uv_deselect(scene, efa, tf, 1);
1626                                                 if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
1627                                                         uvedit_uv_deselect(scene, efa, tf, 2);
1628                                                 if(efa->v4)
1629                                                         if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
1630                                                                 uvedit_uv_deselect(scene, efa, tf, 3);
1631                                         }
1632                                 }
1633                                 flush = -1;
1634                         }
1635                         /* select */
1636                         else {
1637                                 for(efa= em->faces.first; efa; efa= efa->next) {
1638                                         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1639
1640                                         if(uvedit_face_visible(scene, ima, efa, tf)) {
1641                                                 if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
1642                                                         uvedit_uv_select(scene, efa, tf, 0);
1643                                                 if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
1644                                                         uvedit_uv_select(scene, efa, tf, 1);
1645                                                 if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
1646                                                         uvedit_uv_select(scene, efa, tf, 2);
1647                                                 if(efa->v4)
1648                                                         if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
1649                                                                 uvedit_uv_select(scene, efa, tf, 3);
1650                                         }
1651                                 }
1652                                 
1653                                 flush = 1;
1654                         }                       
1655                 }
1656         }
1657         else {
1658                 /* deselect all */
1659                 for(efa= em->faces.first; efa; efa= efa->next) {
1660                         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1661                         uvedit_face_deselect(scene, efa, tf);
1662                 }
1663
1664                 if(selectmode == UV_SELECT_VERTEX) {
1665                         /* select vertex */
1666                         uvedit_uv_select(scene, hit.efa, hit.tf, hit.uv);
1667                         flush= 1;
1668                 }
1669                 else if(selectmode == UV_SELECT_EDGE) {
1670                         /* select edge */
1671                         uvedit_edge_select(scene, hit.efa, hit.tf, hit.edge);
1672                         flush= 1;
1673                 }
1674                 else if(selectmode == UV_SELECT_FACE) {
1675                         /* select face */
1676                         uvedit_face_select(scene, hit.efa, hit.tf);
1677                 }
1678
1679                 /* select sticky uvs */
1680                 if(sticky != SI_STICKY_DISABLE) {
1681                         for(efa= em->faces.first; efa; efa= efa->next) {
1682                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1683                                 if(uvedit_face_visible(scene, ima, efa, tf)) {
1684                                         if(sticky == SI_STICKY_DISABLE) continue;
1685
1686                                         if(sticky_select(limit, hitv, efa->v1->tmp.l, hituv, tf->uv[0], sticky))
1687                                                 uvedit_uv_select(scene, efa, tf, 0);
1688                                         if(sticky_select(limit, hitv, efa->v2->tmp.l, hituv, tf->uv[1], sticky))
1689                                                 uvedit_uv_select(scene, efa, tf, 1);
1690                                         if(sticky_select(limit, hitv, efa->v3->tmp.l, hituv, tf->uv[2], sticky))
1691                                                 uvedit_uv_select(scene, efa, tf, 2);
1692                                         if(efa->v4)
1693                                                 if(sticky_select(limit, hitv, efa->v4->tmp.l, hituv, tf->uv[3], sticky))
1694                                                         uvedit_uv_select(scene, efa, tf, 3);
1695
1696                                         flush= 1;
1697                                 }
1698                         }
1699                 }
1700         }
1701         
1702         if(sync) {
1703                 /* flush for mesh selection */
1704                 if(ts->selectmode != SCE_SELECT_FACE) {
1705                         if(flush==1)            EM_select_flush(em);
1706                         else if(flush==-1)      EM_deselect_flush(em);
1707                 }
1708         }
1709         
1710         DAG_id_tag_update(obedit->data, 0);
1711         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1712         
1713         BKE_mesh_end_editmesh(obedit->data, em);
1714         return OPERATOR_PASS_THROUGH|OPERATOR_FINISHED;
1715 }
1716
1717 static int select_exec(bContext *C, wmOperator *op)
1718 {
1719         float co[2];
1720         int extend, loop;
1721
1722         RNA_float_get_array(op->ptr, "location", co);
1723         extend= RNA_boolean_get(op->ptr, "extend");
1724         loop= 0;
1725
1726         return mouse_select(C, co, extend, loop);
1727 }
1728
1729 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
1730 {
1731         ARegion *ar= CTX_wm_region(C);
1732         float co[2];
1733         int x, y;
1734
1735         x= event->x - ar->winrct.xmin;
1736         y= event->y - ar->winrct.ymin;
1737
1738         UI_view2d_region_to_view(&ar->v2d, x, y, &co[0], &co[1]);
1739         RNA_float_set_array(op->ptr, "location", co);
1740
1741         return select_exec(C, op);
1742 }
1743
1744 static void UV_OT_select(wmOperatorType *ot)
1745 {
1746         /* identifiers */
1747         ot->name= "Select";
1748         ot->description= "Select UV vertice";
1749         ot->idname= "UV_OT_select";
1750         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1751         
1752         /* api callbacks */
1753         ot->exec= select_exec;
1754         ot->invoke= select_invoke;
1755         ot->poll= ED_operator_uvedit;
1756
1757         /* properties */
1758         RNA_def_boolean(ot->srna, "extend", 0,
1759                 "Extend", "Extend selection rather than clearing the existing selection.");
1760         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
1761                 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds.", -100.0f, 100.0f);
1762 }
1763
1764 /* ******************** loop select operator **************** */
1765
1766 static int select_loop_exec(bContext *C, wmOperator *op)
1767 {
1768         float co[2];
1769         int extend, loop;
1770
1771         RNA_float_get_array(op->ptr, "location", co);
1772         extend= RNA_boolean_get(op->ptr, "extend");
1773         loop= 1;
1774
1775         return mouse_select(C, co, extend, loop);
1776 }
1777
1778 static int select_loop_invoke(bContext *C, wmOperator *op, wmEvent *event)
1779 {
1780         ARegion *ar= CTX_wm_region(C);
1781         float co[2];
1782         int x, y;
1783
1784         x= event->x - ar->winrct.xmin;
1785         y= event->y - ar->winrct.ymin;
1786
1787         UI_view2d_region_to_view(&ar->v2d, x, y, &co[0], &co[1]);
1788         RNA_float_set_array(op->ptr, "location", co);
1789
1790         return select_loop_exec(C, op);
1791 }
1792
1793 static void UV_OT_select_loop(wmOperatorType *ot)
1794 {
1795         /* identifiers */
1796         ot->name= "Loop Select";
1797         ot->description= "Select a loop of connected UV vertices";
1798         ot->idname= "UV_OT_select_loop";
1799         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1800         
1801         /* api callbacks */
1802         ot->exec= select_loop_exec;
1803         ot->invoke= select_loop_invoke;
1804         ot->poll= ED_operator_uvedit;
1805
1806         /* properties */
1807         RNA_def_boolean(ot->srna, "extend", 0,
1808                 "Extend", "Extend selection rather than clearing the existing selection.");
1809         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
1810                 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds.", -100.0f, 100.0f);
1811 }
1812
1813 /* ******************** linked select operator **************** */
1814
1815 static int select_linked_internal(bContext *C, wmOperator *op, wmEvent *event, int pick)
1816 {
1817         SpaceImage *sima= CTX_wm_space_image(C);
1818         Scene *scene= CTX_data_scene(C);
1819         ToolSettings *ts= CTX_data_tool_settings(C);
1820         Object *obedit= CTX_data_edit_object(C);
1821         Image *ima= CTX_data_edit_image(C);
1822         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
1823         float limit[2];
1824         int extend;
1825
1826         NearestHit hit, *hit_p= NULL;
1827
1828         if(ts->uv_flag & UV_SYNC_SELECTION) {
1829                 BKE_report(op->reports, RPT_ERROR, "Can't select linked when sync selection is enabled.");
1830                 BKE_mesh_end_editmesh(obedit->data, em);
1831                 return OPERATOR_CANCELLED;
1832         }
1833
1834         extend= RNA_boolean_get(op->ptr, "extend");
1835         uvedit_pixel_to_float(sima, limit, 0.05f);
1836
1837         if(pick) {
1838                 float co[2];
1839
1840                 if(event) {
1841                         /* invoke */
1842                         ARegion *ar= CTX_wm_region(C);
1843                         int x, y;
1844
1845                         x= event->x - ar->winrct.xmin;
1846                         y= event->y - ar->winrct.ymin;
1847
1848                         UI_view2d_region_to_view(&ar->v2d, x, y, &co[0], &co[1]);
1849                         RNA_float_set_array(op->ptr, "location", co);
1850                 }
1851                 else {
1852                         /* exec */
1853                         RNA_float_get_array(op->ptr, "location", co);
1854                 }
1855
1856                 find_nearest_uv_vert(scene, ima, em, co, NULL, &hit);
1857                 hit_p= &hit;
1858         }
1859
1860         select_linked(scene, ima, em, limit, hit_p, extend);
1861
1862         DAG_id_tag_update(obedit->data, 0);
1863         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1864
1865         BKE_mesh_end_editmesh(obedit->data, em);
1866         return OPERATOR_FINISHED;
1867 }
1868
1869 static int select_linked_exec(bContext *C, wmOperator *op)
1870 {
1871         return select_linked_internal(C, op, NULL, 0);
1872 }
1873
1874 static void UV_OT_select_linked(wmOperatorType *ot)
1875 {
1876         /* identifiers */
1877         ot->name= "Select Linked";
1878         ot->description= "Select all UV vertices linked to the active UV map";
1879         ot->idname= "UV_OT_select_linked";
1880         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1881         
1882         /* api callbacks */
1883         ot->exec= select_linked_exec;
1884         ot->poll= ED_operator_uvedit;
1885
1886         /* properties */
1887         RNA_def_boolean(ot->srna, "extend", 0,
1888                 "Extend", "Extend selection rather than clearing the existing selection.");
1889 }
1890
1891 static int select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
1892 {
1893         return select_linked_internal(C, op, event, 1);
1894 }
1895
1896 static int select_linked_pick_exec(bContext *C, wmOperator *op)
1897 {
1898         return select_linked_internal(C, op, NULL, 1);
1899 }
1900
1901 static void UV_OT_select_linked_pick(wmOperatorType *ot)
1902 {
1903         /* identifiers */
1904         ot->name= "Select Linked Pick";
1905         ot->description= "Select all UV vertices linked under the mouse";
1906         ot->idname= "UV_OT_select_linked_pick";
1907         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1908
1909         /* api callbacks */
1910         ot->invoke= select_linked_pick_invoke;
1911         ot->exec= select_linked_pick_exec;
1912         ot->poll= ED_operator_uvedit;
1913
1914         /* properties */
1915         RNA_def_boolean(ot->srna, "extend", 0,
1916                 "Extend", "Extend selection rather than clearing the existing selection.");
1917
1918         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
1919                 "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds.", -100.0f, 100.0f);
1920 }
1921
1922 /* ******************** unlink selection operator **************** */
1923
1924 static int unlink_selection_exec(bContext *C, wmOperator *op)
1925 {
1926         Scene *scene= CTX_data_scene(C);
1927         ToolSettings *ts= CTX_data_tool_settings(C);
1928         Object *obedit= CTX_data_edit_object(C);
1929         Image *ima= CTX_data_edit_image(C);
1930         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
1931         EditFace *efa;
1932         MTFace *tf;
1933
1934         if(ts->uv_flag & UV_SYNC_SELECTION) {
1935                 BKE_report(op->reports, RPT_ERROR, "Can't unlink selection when sync selection is enabled.");
1936                 BKE_mesh_end_editmesh(obedit->data, em);
1937                 return OPERATOR_CANCELLED;
1938         }
1939         
1940         for(efa= em->faces.first; efa; efa= efa->next) {
1941                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
1942
1943                 if(uvedit_face_visible(scene, ima, efa, tf)) {
1944                         const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
1945                         if(~tf->flag & select_flag)
1946                                 tf->flag &= ~select_flag;
1947
1948                 }
1949         }
1950         
1951         DAG_id_tag_update(obedit->data, 0);
1952         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
1953
1954         BKE_mesh_end_editmesh(obedit->data, em);
1955         return OPERATOR_FINISHED;
1956 }
1957
1958 static void UV_OT_unlink_selection(wmOperatorType *ot)
1959 {
1960         /* identifiers */
1961         ot->name= "Unlink Selection";
1962         ot->description= "Unlink selected UV vertices from active UV map";
1963         ot->idname= "UV_OT_unlink_selection";
1964         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1965         
1966         /* api callbacks */
1967         ot->exec= unlink_selection_exec;
1968         ot->poll= ED_operator_uvedit;
1969 }
1970
1971 /* ******************** border select operator **************** */
1972
1973 /* This function sets the selection on tagged faces, need because settings the
1974  * selection a face is done in a number of places but it also needs to respect
1975  * the sticky modes for the UV verts, so dealing with the sticky modes is best
1976  * done in a separate function.
1977  * 
1978  * De-selects faces that have been tagged on efa->tmp.l.  */
1979
1980 static void uv_faces_do_sticky(bContext *C, SpaceImage *sima, Scene *scene, Object *obedit, short select)
1981 {
1982         /* Selecting UV Faces with some modes requires us to change 
1983          * the selection in other faces (depending on the sticky mode).
1984          * 
1985          * This only needs to be done when the Mesh is not used for
1986          * selection (so for sticky modes, vertex or location based). */
1987         
1988         ToolSettings *ts= CTX_data_tool_settings(C);
1989         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
1990         EditFace *efa;
1991         MTFace *tf;
1992         int nverts, i;
1993         
1994         if((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_VERTEX) {
1995                 /* Tag all verts as untouched, then touch the ones that have a face center
1996                  * in the loop and select all MTFace UV's that use a touched vert. */
1997                 EditVert *eve;
1998                 
1999                 for(eve= em->verts.first; eve; eve= eve->next)
2000                         eve->tmp.l = 0;
2001                 
2002                 for(efa= em->faces.first; efa; efa= efa->next) {
2003                         if(efa->tmp.l) {
2004                                 if(efa->v4)
2005                                         efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= efa->v4->tmp.l=1;
2006                                 else
2007                                         efa->v1->tmp.l= efa->v2->tmp.l= efa->v3->tmp.l= 1;
2008                         }
2009                 }
2010
2011                 /* now select tagged verts */
2012                 for(efa= em->faces.first; efa; efa= efa->next) {
2013                         tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);               
2014                         nverts= efa->v4? 4: 3;
2015                         for(i=0; i<nverts; i++) {
2016                                 if((*(&efa->v1 + i))->tmp.l) {
2017                                         if(select)
2018                                                 uvedit_uv_select(scene, efa, tf, i);
2019                                         else
2020                                                 uvedit_uv_deselect(scene, efa, tf, i);
2021                                 }
2022                         }
2023                 }
2024         }
2025         else if((ts->uv_flag & UV_SYNC_SELECTION)==0 && sima->sticky == SI_STICKY_LOC) {
2026                 EditFace *efa_vlist;
2027                 MTFace *tf_vlist;
2028                 UvMapVert *start_vlist=NULL, *vlist_iter;
2029                 struct UvVertMap *vmap;
2030                 float limit[2];
2031                 unsigned int efa_index;
2032                 //EditVert *eve; /* removed vert counting for now */ 
2033                 //int a;
2034                 
2035                 uvedit_pixel_to_float(sima, limit, 0.05);
2036                 
2037                 EM_init_index_arrays(em, 0, 0, 1);
2038                 vmap= EM_make_uv_vert_map(em, 0, 0, limit);
2039                 
2040                 /* verts are numbered above in make_uv_vert_map_EM, make sure this stays true! */
2041                 /*for(a=0, eve= em->verts.first; eve; a++, eve= eve->next)
2042                         eve->tmp.l = a; */
2043                 
2044                 if(vmap == NULL) {
2045                         BKE_mesh_end_editmesh(obedit->data, em);
2046                         return;
2047                 }
2048                 
2049                 for(efa_index=0, efa= em->faces.first; efa; efa_index++, efa= efa->next) {
2050                         if(efa->tmp.l) {
2051                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2052                                 nverts= efa->v4? 4: 3;
2053
2054                                 for(i=0; i<nverts; i++) {
2055                                         if(select)
2056                                                 uvedit_uv_select(scene, efa, tf, i);
2057                                         else
2058                                                 uvedit_uv_deselect(scene, efa, tf, i);
2059                                         
2060                                         vlist_iter= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l);
2061                                         
2062                                         while (vlist_iter) {
2063                                                 if(vlist_iter->separate)
2064                                                         start_vlist = vlist_iter;
2065                                                 
2066                                                 if(efa_index == vlist_iter->f)
2067                                                         break;
2068
2069                                                 vlist_iter = vlist_iter->next;
2070                                         }
2071                                 
2072                                         vlist_iter = start_vlist;
2073                                         while (vlist_iter) {
2074                                                 
2075                                                 if(vlist_iter != start_vlist && vlist_iter->separate)
2076                                                         break;
2077                                                 
2078                                                 if(efa_index != vlist_iter->f) {
2079                                                         efa_vlist = EM_get_face_for_index(vlist_iter->f);
2080                                                         tf_vlist = CustomData_em_get(&em->fdata, efa_vlist->data, CD_MTFACE);
2081                                                         
2082                                                         if(select)
2083                                                                 uvedit_uv_select(scene, efa_vlist, tf_vlist, vlist_iter->tfindex);
2084                                                         else
2085                                                                 uvedit_uv_deselect(scene, efa_vlist, tf_vlist, vlist_iter->tfindex);
2086                                                 }
2087                                                 vlist_iter = vlist_iter->next;
2088                                         }
2089                                 }
2090                         }
2091                 }
2092                 EM_free_index_arrays();
2093                 EM_free_uv_vert_map(vmap);
2094                 
2095         }
2096         else { /* SI_STICKY_DISABLE or ts->uv_flag & UV_SYNC_SELECTION */
2097                 for(efa= em->faces.first; efa; efa= efa->next) {
2098                         if(efa->tmp.l) {
2099                                 tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2100                                 if(select)
2101                                         uvedit_face_select(scene, efa, tf);
2102                                 else
2103                                         uvedit_face_deselect(scene, efa, tf);
2104                         }
2105                 }
2106         }
2107         BKE_mesh_end_editmesh(obedit->data, em);
2108 }
2109
2110 static int border_select_exec(bContext *C, wmOperator *op)
2111 {
2112         SpaceImage *sima= CTX_wm_space_image(C);
2113         Scene *scene= CTX_data_scene(C);
2114         ToolSettings *ts= CTX_data_tool_settings(C);
2115         Object *obedit= CTX_data_edit_object(C);
2116         Image *ima= CTX_data_edit_image(C);
2117         ARegion *ar= CTX_wm_region(C);
2118         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2119         EditFace *efa;
2120         MTFace *tface;
2121         rcti rect;
2122         rctf rectf;
2123         int change, pinned, select, faces;
2124
2125         /* get rectangle from operator */
2126         rect.xmin= RNA_int_get(op->ptr, "xmin");
2127         rect.ymin= RNA_int_get(op->ptr, "ymin");
2128         rect.xmax= RNA_int_get(op->ptr, "xmax");
2129         rect.ymax= RNA_int_get(op->ptr, "ymax");
2130                 
2131         UI_view2d_region_to_view(&ar->v2d, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
2132         UI_view2d_region_to_view(&ar->v2d, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
2133
2134         /* figure out what to select/deselect */
2135         select= (RNA_int_get(op->ptr, "gesture_mode") == GESTURE_MODAL_SELECT);
2136         pinned= RNA_boolean_get(op->ptr, "pinned");
2137         
2138         if(ts->uv_flag & UV_SYNC_SELECTION)
2139                 faces= (ts->selectmode == SCE_SELECT_FACE);
2140         else
2141                 faces= (ts->uv_selectmode == UV_SELECT_FACE);
2142
2143         /* do actual selection */
2144         if(faces && !pinned) {
2145                 /* handle face selection mode */
2146                 float cent[2];
2147
2148                 change= 0;
2149
2150                 for(efa= em->faces.first; efa; efa= efa->next) {
2151                         /* assume not touched */
2152                         efa->tmp.l = 0;
2153                         tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2154                         if(uvedit_face_visible(scene, ima, efa, tface)) {
2155                                 uv_center(tface->uv, cent, efa->v4 != NULL);
2156                                 if(BLI_in_rctf(&rectf, cent[0], cent[1])) {
2157                                         efa->tmp.l = change = 1;
2158                                 }
2159                         }
2160                 }
2161
2162                 /* (de)selects all tagged faces and deals with sticky modes */
2163                 if(change)
2164                         uv_faces_do_sticky(C, sima, scene, obedit, select);
2165         }
2166         else {
2167                 /* other selection modes */
2168                 change= 1;
2169
2170                 for(efa= em->faces.first; efa; efa= efa->next) {
2171                         tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2172                         if(uvedit_face_visible(scene, ima, efa, tface)) {
2173                                 if(!pinned || (ts->uv_flag & UV_SYNC_SELECTION) ) {
2174                                         /* UV_SYNC_SELECTION - can't do pinned selection */
2175                                         if(BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
2176                                                 if(select)      uvedit_uv_select(scene, efa, tface, 0);
2177                                                 else            uvedit_uv_deselect(scene, efa, tface, 0);
2178                                         }
2179                                         if(BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
2180                                                 if(select)      uvedit_uv_select(scene, efa, tface, 1);
2181                                                 else            uvedit_uv_deselect(scene, efa, tface, 1);
2182                                         }
2183                                         if(BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
2184                                                 if(select)      uvedit_uv_select(scene, efa, tface, 2);
2185                                                 else            uvedit_uv_deselect(scene, efa, tface, 2);
2186                                         }
2187                                         if(efa->v4 && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
2188                                                 if(select)      uvedit_uv_select(scene, efa, tface, 3);
2189                                                 else            uvedit_uv_deselect(scene, efa, tface, 3);
2190                                         }
2191                                 }
2192                                 else if(pinned) {
2193                                         if((tface->unwrap & TF_PIN1) && 
2194                                                 BLI_in_rctf(&rectf, tface->uv[0][0], tface->uv[0][1])) {
2195                                                 
2196                                                 if(select)      uvedit_uv_select(scene, efa, tface, 0);
2197                                                 else            uvedit_uv_deselect(scene, efa, tface, 0);
2198                                         }
2199                                         if((tface->unwrap & TF_PIN2) && 
2200                                                 BLI_in_rctf(&rectf, tface->uv[1][0], tface->uv[1][1])) {
2201                                                 
2202                                                 if(select)      uvedit_uv_select(scene, efa, tface, 1);
2203                                                 else            uvedit_uv_deselect(scene, efa, tface, 1);
2204                                         }
2205                                         if((tface->unwrap & TF_PIN3) && 
2206                                                 BLI_in_rctf(&rectf, tface->uv[2][0], tface->uv[2][1])) {
2207                                                 
2208                                                 if(select)      uvedit_uv_select(scene, efa, tface, 2);
2209                                                 else            uvedit_uv_deselect(scene, efa, tface, 2);
2210                                         }
2211                                         if((efa->v4) && (tface->unwrap & TF_PIN4) && BLI_in_rctf(&rectf, tface->uv[3][0], tface->uv[3][1])) {
2212                                                 if(select)      uvedit_uv_select(scene, efa, tface, 3);
2213                                                 else            uvedit_uv_deselect(scene, efa, tface, 3);
2214                                         }
2215                                 }
2216                         }
2217                 }
2218         }
2219
2220         if(change) {
2221                 /* make sure newly selected vert selection is updated*/
2222                 if(ts->uv_flag & UV_SYNC_SELECTION) {
2223                         if(ts->selectmode != SCE_SELECT_FACE) {
2224                                 if(select)      EM_select_flush(em);
2225                                 else            EM_deselect_flush(em);
2226                         }
2227                 }
2228
2229                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2230                 
2231                 BKE_mesh_end_editmesh(obedit->data, em);
2232                 return OPERATOR_FINISHED;
2233         }
2234         
2235         BKE_mesh_end_editmesh(obedit->data, em);
2236         return OPERATOR_CANCELLED;
2237
2238
2239 static void UV_OT_select_border(wmOperatorType *ot)
2240 {
2241         /* identifiers */
2242         ot->name= "Border Select";
2243         ot->description= "Select UV vertices using border selection";
2244         ot->idname= "UV_OT_select_border";
2245         
2246         /* api callbacks */
2247         ot->invoke= WM_border_select_invoke;
2248         ot->exec= border_select_exec;
2249         ot->modal= WM_border_select_modal;
2250         ot->poll= ED_operator_uvedit;
2251         
2252         /* flags */
2253         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2254         
2255         /* properties */
2256         RNA_def_boolean(ot->srna, "pinned", 0, "Pinned", "Border select pinned UVs only.");
2257
2258         WM_operator_properties_gesture_border(ot, FALSE);
2259 }
2260
2261 /* ******************** circle select operator **************** */
2262
2263 static void select_uv_inside_ellipse(Scene *scene, int select, EditFace *efa, MTFace *tface, int index, float *offset, float *ell, int select_index)
2264 {
2265         /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
2266         float x, y, r2, *uv;
2267         
2268         uv= tface->uv[index];
2269
2270         x= (uv[0] - offset[0])*ell[0];
2271         y= (uv[1] - offset[1])*ell[1];
2272
2273         r2 = x*x + y*y;
2274         if(r2 < 1.0) {
2275                 if(select)      uvedit_uv_select(scene, efa, tface, select_index);
2276                 else uvedit_uv_deselect(scene, efa, tface, select_index);
2277         }
2278 }
2279
2280 static int circle_select_exec(bContext *C, wmOperator *op)
2281 {
2282         SpaceImage *sima= CTX_wm_space_image(C);
2283         Scene *scene= CTX_data_scene(C);
2284         Object *obedit= CTX_data_edit_object(C);
2285         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2286         ARegion *ar= CTX_wm_region(C);
2287         EditFace *efa;
2288         MTFace *tface;
2289         int x, y, radius, width, height, select;
2290         float zoomx, zoomy, offset[2], ellipse[2];
2291         int gesture_mode= RNA_int_get(op->ptr, "gesture_mode");
2292     
2293         /* get operator properties */
2294         select= (gesture_mode == GESTURE_MODAL_SELECT);
2295         x= RNA_int_get(op->ptr, "x");
2296         y= RNA_int_get(op->ptr, "y");
2297         radius= RNA_int_get(op->ptr, "radius");
2298
2299         /* compute ellipse size and location, not a circle since we deal
2300          * with non square image. ellipse is normalized, r = 1.0. */
2301         ED_space_image_size(sima, &width, &height);
2302         ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
2303
2304         ellipse[0]= width*zoomx/radius;
2305         ellipse[1]= height*zoomy/radius;
2306
2307         UI_view2d_region_to_view(&ar->v2d, x, y, &offset[0], &offset[1]);
2308         
2309         /* do selection */
2310         for(efa= em->faces.first; efa; efa= efa->next) {
2311                 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2312                 select_uv_inside_ellipse(scene, select, efa, tface, 0, offset, ellipse, 0);
2313                 select_uv_inside_ellipse(scene, select, efa, tface, 1, offset, ellipse, 1);
2314                 select_uv_inside_ellipse(scene, select, efa, tface, 2, offset, ellipse, 2);
2315                 if(efa->v4)
2316                         select_uv_inside_ellipse(scene, select, efa, tface, 3, offset, ellipse, 3);
2317         }
2318
2319         if(select) EM_select_flush(em);
2320         else EM_deselect_flush(em);
2321
2322         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2323
2324         BKE_mesh_end_editmesh(obedit->data, em);
2325         return OPERATOR_FINISHED;
2326 }
2327
2328 static void UV_OT_circle_select(wmOperatorType *ot)
2329 {
2330         /* identifiers */
2331         ot->name= "Circle Select";
2332         ot->description= "Select UV vertices using circle selection";
2333         ot->idname= "UV_OT_circle_select";
2334         
2335         /* api callbacks */
2336         ot->invoke= WM_gesture_circle_invoke;
2337         ot->modal= WM_gesture_circle_modal;
2338         ot->exec= circle_select_exec;
2339         ot->poll= ED_operator_uvedit;
2340         
2341         /* flags */
2342         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2343         
2344         /* properties */
2345         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
2346         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
2347         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
2348         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
2349 }
2350
2351 /* ******************** snap cursor operator **************** */
2352
2353 static void snap_uv_to_pixel(float *uvco, float w, float h)
2354 {
2355         uvco[0] = ((float)((int)((uvco[0]*w) + 0.5f)))/w;
2356         uvco[1] = ((float)((int)((uvco[1]*h) + 0.5f)))/h;
2357 }
2358
2359 static void snap_cursor_to_pixels(SpaceImage *sima)
2360 {
2361         int width= 0, height= 0;
2362
2363         ED_space_image_size(sima, &width, &height);
2364         snap_uv_to_pixel(sima->cursor, width, height);
2365 }
2366
2367 static int snap_cursor_to_selection(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
2368 {
2369         return uvedit_center(scene, ima, obedit, sima->cursor, 0);
2370 }
2371
2372 static int snap_cursor_exec(bContext *C, wmOperator *op)
2373 {
2374         SpaceImage *sima= CTX_wm_space_image(C);
2375         Scene *scene= CTX_data_scene(C);
2376         Object *obedit= CTX_data_edit_object(C);
2377         Image *ima= CTX_data_edit_image(C);
2378         int change= 0;
2379
2380         switch(RNA_boolean_get(op->ptr, "target")) {
2381                 case 0:
2382                         snap_cursor_to_pixels(sima);
2383                         change= 1;
2384                         break;
2385                 case 1:
2386                         change= snap_cursor_to_selection(scene, ima, obedit, sima);
2387                         break;
2388         }
2389
2390         if(!change)
2391                 return OPERATOR_CANCELLED;
2392         
2393         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_IMAGE, sima);
2394
2395         return OPERATOR_FINISHED;
2396 }
2397
2398 static void UV_OT_snap_cursor(wmOperatorType *ot)
2399 {
2400         static EnumPropertyItem target_items[] = {
2401                 {0, "PIXELS", 0, "Pixels", ""},
2402                 {1, "SELECTION", 0, "Selection", ""},
2403                 {0, NULL, 0, NULL, NULL}};
2404
2405         /* identifiers */
2406         ot->name= "Snap Cursor";
2407         ot->description= "Snap cursor to target type";
2408         ot->idname= "UV_OT_snap_cursor";
2409         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2410         
2411         /* api callbacks */
2412         ot->exec= snap_cursor_exec;
2413         ot->poll= ED_operator_uvedit;
2414
2415         /* properties */
2416         RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UV's to.");
2417 }
2418
2419 /* ******************** snap selection operator **************** */
2420
2421 static int snap_uvs_to_cursor(Scene *scene, Image *ima, Object *obedit, SpaceImage *sima)
2422 {
2423         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2424         EditFace *efa;
2425         MTFace *tface;
2426         short change= 0;
2427
2428         for(efa= em->faces.first; efa; efa= efa->next) {
2429                 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2430                 if(uvedit_face_visible(scene, ima, efa, tface)) {
2431                         if(uvedit_uv_selected(scene, efa, tface, 0))            VECCOPY2D(tface->uv[0], sima->cursor);
2432                         if(uvedit_uv_selected(scene, efa, tface, 1))            VECCOPY2D(tface->uv[1], sima->cursor);
2433                         if(uvedit_uv_selected(scene, efa, tface, 2))            VECCOPY2D(tface->uv[2], sima->cursor);
2434                         if(efa->v4)
2435                                 if(uvedit_uv_selected(scene, efa, tface, 3))    VECCOPY2D(tface->uv[3], sima->cursor);
2436
2437                         change= 1;
2438                 }
2439         }
2440
2441         BKE_mesh_end_editmesh(obedit->data, em);
2442         return change;
2443 }
2444
2445 static int snap_uvs_to_adjacent_unselected(Scene *scene, Image *ima, Object *obedit)
2446 {
2447         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2448         EditFace *efa;
2449         EditVert *eve;
2450         MTFace *tface;
2451         short change = 0;
2452         int count = 0;
2453         float *coords;
2454         short *usercount, users;
2455         
2456         /* set all verts to -1 : an unused index*/
2457         for(eve= em->verts.first; eve; eve= eve->next)
2458                 eve->tmp.l=-1;
2459         
2460         /* index every vert that has a selected UV using it, but only once so as to
2461          * get unique indices and to count how much to malloc */
2462         for(efa= em->faces.first; efa; efa= efa->next) {
2463                 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2464
2465                 if(uvedit_face_visible(scene, ima, efa, tface)) {
2466                         if(uvedit_uv_selected(scene, efa, tface, 0) && efa->v1->tmp.l==-1)              efa->v1->tmp.l= count++;
2467                         if(uvedit_uv_selected(scene, efa, tface, 1) && efa->v2->tmp.l==-1)              efa->v2->tmp.l= count++;
2468                         if(uvedit_uv_selected(scene, efa, tface, 2) && efa->v3->tmp.l==-1)              efa->v3->tmp.l= count++;
2469                         if(efa->v4)
2470                                 if(uvedit_uv_selected(scene, efa, tface, 3) && efa->v4->tmp.l==-1)      efa->v4->tmp.l= count++;
2471
2472                         change = 1;
2473                         
2474                         /* optional speedup */
2475                         efa->tmp.p = tface;
2476                 }
2477                 else
2478                         efa->tmp.p = NULL;
2479         }
2480         
2481         coords = MEM_callocN(sizeof(float)*count*2, "snap to adjacent coords");
2482         usercount = MEM_callocN(sizeof(short)*count, "snap to adjacent counts");
2483         
2484         /* add all UV coords from visible, unselected UV coords as well as counting them to average later */
2485         for(efa= em->faces.first; efa; efa= efa->next) {
2486                 if((tface=(MTFace *)efa->tmp.p)) {
2487                         /* is this an unselected UV we can snap to? */
2488                         if(efa->v1->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 0))) {
2489                                 coords[efa->v1->tmp.l*2] +=             tface->uv[0][0];
2490                                 coords[(efa->v1->tmp.l*2)+1] += tface->uv[0][1];
2491                                 usercount[efa->v1->tmp.l]++;
2492                                 change = 1;
2493                         }
2494                         if(efa->v2->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 1))) {
2495                                 coords[efa->v2->tmp.l*2] +=             tface->uv[1][0];
2496                                 coords[(efa->v2->tmp.l*2)+1] += tface->uv[1][1];
2497                                 usercount[efa->v2->tmp.l]++;
2498                                 change = 1;
2499                         }
2500                         if(efa->v3->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 2))) {
2501                                 coords[efa->v3->tmp.l*2] +=             tface->uv[2][0];
2502                                 coords[(efa->v3->tmp.l*2)+1] += tface->uv[2][1];
2503                                 usercount[efa->v3->tmp.l]++;
2504                                 change = 1;
2505                         }
2506                         
2507                         if(efa->v4) {
2508                                 if(efa->v4->tmp.l >= 0 && (!uvedit_uv_selected(scene, efa, tface, 3))) {
2509                                         coords[efa->v4->tmp.l*2] +=             tface->uv[3][0];
2510                                         coords[(efa->v4->tmp.l*2)+1] += tface->uv[3][1];
2511                                         usercount[efa->v4->tmp.l]++;
2512                                         change = 1;
2513                                 }
2514                         }
2515                 }
2516         }
2517         
2518         /* no other verts selected, bail out */
2519         if(!change) {
2520                 MEM_freeN(coords);
2521                 MEM_freeN(usercount);
2522                 BKE_mesh_end_editmesh(obedit->data, em);
2523                 return change;
2524         }
2525         
2526         /* copy the averaged unselected UVs back to the selected UVs */
2527         for(efa= em->faces.first; efa; efa= efa->next) {
2528                 if((tface=(MTFace *)efa->tmp.p)) {
2529                         
2530                         if(     uvedit_uv_selected(scene, efa, tface, 0) &&
2531                                         efa->v1->tmp.l >= 0 &&
2532                                         (users = usercount[efa->v1->tmp.l])
2533                         ) {
2534                                 tface->uv[0][0] = coords[efa->v1->tmp.l*2]              / users;
2535                                 tface->uv[0][1] = coords[(efa->v1->tmp.l*2)+1]  / users;
2536                         }
2537
2538                         if(     uvedit_uv_selected(scene, efa, tface, 1) &&
2539                                         efa->v2->tmp.l >= 0 &&
2540                                         (users = usercount[efa->v2->tmp.l])
2541                         ) {
2542                                 tface->uv[1][0] = coords[efa->v2->tmp.l*2]              / users;
2543                                 tface->uv[1][1] = coords[(efa->v2->tmp.l*2)+1]  / users;
2544                         }
2545                         
2546                         if(     uvedit_uv_selected(scene, efa, tface, 2) &&
2547                                         efa->v3->tmp.l >= 0 &&
2548                                         (users = usercount[efa->v3->tmp.l])
2549                         ) {
2550                                 tface->uv[2][0] = coords[efa->v3->tmp.l*2]              / users;
2551                                 tface->uv[2][1] = coords[(efa->v3->tmp.l*2)+1]  / users;
2552                         }
2553                         
2554                         if(efa->v4) {
2555                                 if(     uvedit_uv_selected(scene, efa, tface, 3) &&
2556                                                 efa->v4->tmp.l >= 0 &&
2557                                                 (users = usercount[efa->v4->tmp.l])
2558                                 ) {
2559                                         tface->uv[3][0] = coords[efa->v4->tmp.l*2]              / users;
2560                                         tface->uv[3][1] = coords[(efa->v4->tmp.l*2)+1]  / users;
2561                                 }
2562                         }
2563                 }
2564         }
2565         
2566         MEM_freeN(coords);
2567         MEM_freeN(usercount);
2568
2569         BKE_mesh_end_editmesh(obedit->data, em);
2570         return change;
2571 }
2572
2573 static int snap_uvs_to_pixels(SpaceImage *sima, Scene *scene, Object *obedit)
2574 {
2575         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2576         Image *ima;
2577         EditFace *efa;
2578         MTFace *tface;
2579         int width= 0, height= 0;
2580         float w, h;
2581         short change = 0;
2582
2583         if(!sima)
2584                 return 0;
2585         
2586         ima= sima->image;
2587         
2588         ED_space_image_size(sima, &width, &height);
2589         w = (float)width;
2590         h = (float)height;
2591         
2592         for(efa= em->faces.first; efa; efa= efa->next) {
2593                 tface= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2594                 if(uvedit_face_visible(scene, ima, efa, tface)) {
2595                         if(uvedit_uv_selected(scene, efa, tface, 0)) snap_uv_to_pixel(tface->uv[0], w, h);
2596                         if(uvedit_uv_selected(scene, efa, tface, 1)) snap_uv_to_pixel(tface->uv[1], w, h);
2597                         if(uvedit_uv_selected(scene, efa, tface, 2)) snap_uv_to_pixel(tface->uv[2], w, h);
2598                         if(efa->v4)
2599                                 if(uvedit_uv_selected(scene, efa, tface, 3)) snap_uv_to_pixel(tface->uv[3], w, h);
2600
2601                         change = 1;
2602                 }
2603         }
2604
2605         BKE_mesh_end_editmesh(obedit->data, em);
2606         return change;
2607 }
2608
2609 static int snap_selection_exec(bContext *C, wmOperator *op)
2610 {
2611         SpaceImage *sima= CTX_wm_space_image(C);
2612         Scene *scene= CTX_data_scene(C);
2613         Object *obedit= CTX_data_edit_object(C);
2614         Image *ima= CTX_data_edit_image(C);
2615         int change= 0;
2616
2617         switch(RNA_boolean_get(op->ptr, "target")) {
2618                 case 0:
2619                         change= snap_uvs_to_pixels(sima, scene, obedit);
2620                         break;
2621                 case 1:
2622                         change= snap_uvs_to_cursor(scene, ima, obedit, sima);
2623                         break;
2624                 case 2:
2625                         change= snap_uvs_to_adjacent_unselected(scene, ima, obedit);
2626                         break;
2627         }
2628
2629         if(!change)
2630                 return OPERATOR_CANCELLED;
2631         
2632         DAG_id_tag_update(obedit->data, 0);
2633         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2634
2635         return OPERATOR_FINISHED;
2636 }
2637
2638 static void UV_OT_snap_selection(wmOperatorType *ot)
2639 {
2640         static EnumPropertyItem target_items[] = {
2641                 {0, "PIXELS", 0, "Pixels", ""},
2642                 {1, "CURSOR", 0, "Cursor", ""},
2643                 {2, "ADJACENT_UNSELECTED", 0, "Adjacent Unselected", ""},
2644                 {0, NULL, 0, NULL, NULL}};
2645
2646         /* identifiers */
2647         ot->name= "Snap Selection";
2648         ot->description= "Snap selected UV vertices to target type";
2649         ot->idname= "UV_OT_snap_selection";
2650         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2651         
2652         /* api callbacks */
2653         ot->exec= snap_selection_exec;
2654         ot->poll= ED_operator_uvedit;
2655
2656         /* properties */
2657         RNA_def_enum(ot->srna, "target", target_items, 0, "Target", "Target to snap the selected UV's to.");
2658 }
2659
2660 /* ******************** pin operator **************** */
2661
2662 static int pin_exec(bContext *C, wmOperator *op)
2663 {
2664         Scene *scene= CTX_data_scene(C);
2665         Object *obedit= CTX_data_edit_object(C);
2666         Image *ima= CTX_data_edit_image(C);
2667         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2668         EditFace *efa;
2669         MTFace *tface;
2670         int clear= RNA_boolean_get(op->ptr, "clear");
2671         
2672         for(efa= em->faces.first; efa; efa= efa->next) {
2673                 tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2674
2675                 if(uvedit_face_visible(scene, ima, efa, tface)) {
2676                         if(!clear) {
2677                                 if(uvedit_uv_selected(scene, efa, tface, 0)) tface->unwrap |= TF_PIN1;
2678                                 if(uvedit_uv_selected(scene, efa, tface, 1)) tface->unwrap |= TF_PIN2;
2679                                 if(uvedit_uv_selected(scene, efa, tface, 2)) tface->unwrap |= TF_PIN3;
2680                                 if(efa->v4)
2681                                         if(uvedit_uv_selected(scene, efa, tface, 3)) tface->unwrap |= TF_PIN4;
2682                         }
2683                         else {
2684                                 if(uvedit_uv_selected(scene, efa, tface, 0)) tface->unwrap &= ~TF_PIN1;
2685                                 if(uvedit_uv_selected(scene, efa, tface, 1)) tface->unwrap &= ~TF_PIN2;
2686                                 if(uvedit_uv_selected(scene, efa, tface, 2)) tface->unwrap &= ~TF_PIN3;
2687                                 if(efa->v4)
2688                                         if(uvedit_uv_selected(scene, efa, tface, 3)) tface->unwrap &= ~TF_PIN4;
2689                         }
2690                 }
2691         }
2692         
2693         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
2694
2695         BKE_mesh_end_editmesh(obedit->data, em);
2696         return OPERATOR_FINISHED;
2697 }
2698
2699 static void UV_OT_pin(wmOperatorType *ot)
2700 {
2701         /* identifiers */
2702         ot->name= "Pin";
2703         ot->description= "Set/clear selected UV vertices as anchored between multiple unwrap operations";
2704         ot->idname= "UV_OT_pin";
2705         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2706         
2707         /* api callbacks */
2708         ot->exec= pin_exec;
2709         ot->poll= ED_operator_uvedit;
2710
2711         /* properties */
2712         RNA_def_boolean(ot->srna, "clear", 0, "Clear", "Clear pinning for the selection instead of setting it.");
2713 }
2714
2715 /******************* select pinned operator ***************/
2716
2717 static int select_pinned_exec(bContext *C, wmOperator *UNUSED(op))
2718 {
2719         Scene *scene= CTX_data_scene(C);
2720         Object *obedit= CTX_data_edit_object(C);
2721         Image *ima= CTX_data_edit_image(C);
2722         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2723         EditFace *efa;
2724         MTFace *tface;
2725         
2726         for(efa= em->faces.first; efa; efa= efa->next) {
2727                 tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2728
2729                 if(uvedit_face_visible(scene, ima, efa, tface)) {
2730                         if(tface->unwrap & TF_PIN1) uvedit_uv_select(scene, efa, tface, 0);
2731                         if(tface->unwrap & TF_PIN2) uvedit_uv_select(scene, efa, tface, 1);
2732                         if(tface->unwrap & TF_PIN3) uvedit_uv_select(scene, efa, tface, 2);
2733                         if(efa->v4) {
2734                                 if(tface->unwrap & TF_PIN4) uvedit_uv_select(scene, efa, tface, 3);
2735                         }
2736                 }
2737         }
2738         
2739         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2740
2741         BKE_mesh_end_editmesh(obedit->data, em);
2742         return OPERATOR_FINISHED;
2743 }
2744
2745 static void UV_OT_select_pinned(wmOperatorType *ot)
2746 {
2747         /* identifiers */
2748         ot->name= "Selected Pinned";
2749         ot->description= "Select all pinned UV vertices";
2750         ot->idname= "UV_OT_select_pinned";
2751         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2752         
2753         /* api callbacks */
2754         ot->exec= select_pinned_exec;
2755         ot->poll= ED_operator_uvedit;
2756 }
2757
2758 /********************** hide operator *********************/
2759
2760 static int hide_exec(bContext *C, wmOperator *op)
2761 {
2762         SpaceImage *sima= CTX_wm_space_image(C);
2763         ToolSettings *ts= CTX_data_tool_settings(C);
2764         Object *obedit= CTX_data_edit_object(C);
2765         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2766         EditFace *efa;
2767         MTFace *tf;
2768         int swap= RNA_boolean_get(op->ptr, "unselected");
2769         int facemode= sima ? sima->flag & SI_SELACTFACE : 0;
2770
2771         if(ts->uv_flag & UV_SYNC_SELECTION) {
2772                 EM_hide_mesh(em, swap);
2773                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2774
2775                 BKE_mesh_end_editmesh(obedit->data, em);
2776                 return OPERATOR_FINISHED;
2777         }
2778         
2779         if(swap) {
2780                 for(efa= em->faces.first; efa; efa= efa->next) {
2781                         if(efa->f & SELECT) {
2782                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2783                                 if(facemode) {
2784                                         /* Pretend face mode */
2785                                         if((    (efa->v4==NULL && 
2786                                                         (       tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) ==                        (TF_SEL1|TF_SEL2|TF_SEL3) )                      ||
2787                                                         (       tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) ==        (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)       ) == 0) {
2788                                                 
2789                                                 if(em->selectmode == SCE_SELECT_FACE) {
2790                                                         efa->f &= ~SELECT;
2791                                                         /* must re-select after */
2792                                                         efa->e1->f &= ~SELECT;
2793                                                         efa->e2->f &= ~SELECT;
2794                                                         efa->e3->f &= ~SELECT;
2795                                                         if(efa->e4) efa->e4->f &= ~SELECT;
2796                                                 }
2797                                                 else
2798                                                         EM_select_face(efa, 0);
2799                                         }
2800                                         tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2801                                 }
2802                                 else if(em->selectmode == SCE_SELECT_FACE) {
2803                                         const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
2804                                         if((tf->flag & select_flag)==0) {
2805                                                 EM_select_face(efa, 0);
2806                                                 tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2807                                         }
2808                                 }
2809                                 else {
2810                                         /* EM_deselect_flush will deselect the face */
2811                                         if((tf->flag & TF_SEL1)==0)                             efa->v1->f &= ~SELECT;
2812                                         if((tf->flag & TF_SEL2)==0)                             efa->v2->f &= ~SELECT;
2813                                         if((tf->flag & TF_SEL3)==0)                             efa->v3->f &= ~SELECT;
2814                                         if((efa->v4) && (tf->flag & TF_SEL4)==0)        efa->v4->f &= ~SELECT;                  
2815
2816                                         tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2817                                 }
2818                         }
2819                 }
2820         }
2821         else {
2822                 for(efa= em->faces.first; efa; efa= efa->next) {
2823                         if(efa->f & SELECT) {
2824                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2825
2826                                 if(facemode) {
2827                                         if(     (efa->v4==NULL && 
2828                                                         (       tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) ==                        (TF_SEL1|TF_SEL2|TF_SEL3) )                      ||
2829                                                         (       tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)) ==        (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4)       ) {
2830                                                 
2831                                                 if(em->selectmode == SCE_SELECT_FACE) {
2832                                                         efa->f &= ~SELECT;
2833                                                         /* must re-select after */
2834                                                         efa->e1->f &= ~SELECT;
2835                                                         efa->e2->f &= ~SELECT;
2836                                                         efa->e3->f &= ~SELECT;
2837                                                         if(efa->e4) efa->e4->f &= ~SELECT;
2838                                                 }
2839                                                 else
2840                                                         EM_select_face(efa, 0);
2841                                         }
2842
2843                                         tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2844                                 }
2845                                 else if(em->selectmode == SCE_SELECT_FACE) {
2846                                         const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
2847                                         if(tf->flag & select_flag)
2848                                                 EM_select_face(efa, 0);
2849
2850                                         tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2851                                 }
2852                                 else {
2853                                         /* EM_deselect_flush will deselect the face */
2854                                         if(tf->flag & TF_SEL1)                          efa->v1->f &= ~SELECT;
2855                                         if(tf->flag & TF_SEL2)                          efa->v2->f &= ~SELECT;
2856                                         if(tf->flag & TF_SEL3)                          efa->v3->f &= ~SELECT;
2857                                         if((efa->v4) && tf->flag & TF_SEL4)     efa->v4->f &= ~SELECT;
2858
2859                                         tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
2860                                 }
2861                         }
2862                 }
2863         }
2864         
2865         /*deselects too many but ok for now*/
2866         if(em->selectmode & (SCE_SELECT_EDGE|SCE_SELECT_VERTEX))
2867                 EM_deselect_flush(em);
2868         
2869         if(em->selectmode==SCE_SELECT_FACE) {
2870                 /* de-selected all edges from faces that were de-selected.
2871                  * now make sure all faces that are selected also have selected edges */
2872                 for(efa= em->faces.first; efa; efa= efa->next)
2873                         if(efa->f & SELECT)
2874                                 EM_select_face(efa, 1);
2875         }
2876         
2877         EM_validate_selections(em);
2878         WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2879
2880         BKE_mesh_end_editmesh(obedit->data, em);
2881         return OPERATOR_FINISHED;
2882 }
2883
2884 static void UV_OT_hide(wmOperatorType *ot)
2885 {
2886         /* identifiers */
2887         ot->name= "Hide Selected";
2888         ot->description= "Hide (un)selected UV vertices";
2889         ot->idname= "UV_OT_hide";
2890         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2891         
2892         /* api callbacks */
2893         ot->exec= hide_exec;
2894         ot->poll= ED_operator_uvedit;
2895
2896         /* props */
2897         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected.");
2898 }
2899
2900 /****************** reveal operator ******************/
2901
2902 static int reveal_exec(bContext *C, wmOperator *UNUSED(op))
2903 {
2904         SpaceImage *sima= CTX_wm_space_image(C);
2905         ToolSettings *ts= CTX_data_tool_settings(C);
2906         Object *obedit= CTX_data_edit_object(C);
2907         EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
2908         EditFace *efa;
2909         MTFace *tf;
2910         int facemode= sima ? sima->flag & SI_SELACTFACE : 0;
2911         int stickymode= sima ? (sima->sticky != SI_STICKY_DISABLE) : 1;
2912         
2913         /* call the mesh function if we are in mesh sync sel */
2914         if(ts->uv_flag & UV_SYNC_SELECTION) {
2915                 EM_reveal_mesh(em);
2916                 WM_event_add_notifier(C, NC_GEOM|ND_SELECT, obedit->data);
2917
2918                 BKE_mesh_end_editmesh(obedit->data, em);
2919                 return OPERATOR_FINISHED;
2920         }
2921         
2922         if(facemode) {
2923                 if(em->selectmode == SCE_SELECT_FACE) {
2924                         for(efa= em->faces.first; efa; efa= efa->next) {
2925                                 if(!(efa->h) && !(efa->f & SELECT)) {
2926                                         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2927                                         EM_select_face(efa, 1);
2928                                         tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
2929                                 }
2930                         }
2931                 }
2932                 else {
2933                         /* enable adjacent faces to have disconnected UV selections if sticky is disabled */
2934                         if(!stickymode) {
2935                                 for(efa= em->faces.first; efa; efa= efa->next) {
2936                                         if(!(efa->h) && !(efa->f & SELECT)) {
2937                                                 /* All verts must be unselected for the face to be selected in the UV view */
2938                                                 if((efa->v1->f&SELECT)==0 && (efa->v2->f&SELECT)==0 && (efa->v3->f&SELECT)==0 && (efa->v4==0 || (efa->v4->f&SELECT)==0)) {
2939                                                         tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2940
2941                                                         tf->flag |= TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4;
2942                                                         /* Cant use EM_select_face here because it unselects the verts
2943                                                          * and we cant tell if the face was totally unselected or not */
2944                                                         /*EM_select_face(efa, 1);
2945                                                          * 
2946                                                          * See Loop with EM_select_face() below... */
2947                                                         efa->f |= SELECT;
2948                                                 }
2949                                         }
2950                                 }
2951                         }
2952                         else {
2953                                 for(efa= em->faces.first; efa; efa= efa->next) {
2954                                         if(!(efa->h) && !(efa->f & SELECT)) {
2955                                                 tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
2956
2957                                                 if((efa->v1->f & SELECT)==0)                            {tf->flag |= TF_SEL1;}
2958                             &nbs