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