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