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