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