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