mask selection invert wasnt working.
[blender.git] / source / blender / editors / mask / mask_select.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) 2012 Blender Foundation.
19  * All rights reserved.
20  *
21  *
22  * Contributor(s): Blender Foundation,
23  *                 Sergey Sharybin
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/editors/mask/mask_select.c
29  *  \ingroup edmask
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_utildefines.h"
35 #include "BLI_rect.h"
36 #include "BLI_lasso.h"
37
38 #include "BKE_context.h"
39 #include "BKE_mask.h"
40
41 #include "DNA_mask_types.h"
42 #include "DNA_object_types.h"  /* SELECT */
43
44 #include "WM_api.h"
45 #include "WM_types.h"
46
47 #include "ED_screen.h"
48 #include "ED_clip.h"
49 #include "ED_mask.h"  /* own include */
50
51 #include "RNA_access.h"
52 #include "RNA_define.h"
53
54 #include "mask_intern.h"  /* own include */
55
56 /* 'check' select */
57 int ED_mask_spline_select_check(MaskSpline *spline)
58 {
59         int i;
60
61         for (i = 0; i < spline->tot_point; i++) {
62                 MaskSplinePoint *point = &spline->points[i];
63
64                 if (MASKPOINT_ISSEL_ANY(point))
65                         return TRUE;
66         }
67
68         return FALSE;
69 }
70
71 int ED_mask_layer_select_check(MaskLayer *masklay)
72 {
73         MaskSpline *spline;
74
75         if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
76                 return FALSE;
77         }
78
79         for (spline = masklay->splines.first; spline; spline = spline->next) {
80                 if (ED_mask_spline_select_check(spline)) {
81                         return TRUE;
82                 }
83         }
84
85         return FALSE;
86 }
87
88 int ED_mask_select_check(Mask *mask)
89 {
90         MaskLayer *masklay;
91
92         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
93                 if (ED_mask_layer_select_check(masklay)) {
94                         return TRUE;
95                 }
96         }
97
98         return FALSE;
99 }
100
101 /* 'sel' select  */
102 void ED_mask_spline_select_set(MaskSpline *spline, const short do_select)
103 {
104         int i;
105
106         if (do_select)
107                 spline->flag |= SELECT;
108         else
109                 spline->flag &= ~SELECT;
110
111         for (i = 0; i < spline->tot_point; i++) {
112                 MaskSplinePoint *point = &spline->points[i];
113
114                 BKE_mask_point_select_set(point, do_select);
115         }
116 }
117
118 void ED_mask_layer_select_set(MaskLayer *masklay, const short do_select)
119 {
120         MaskSpline *spline;
121
122         if (masklay->restrictflag & MASK_RESTRICT_SELECT) {
123                 if (do_select == TRUE) {
124                         return;
125                 }
126         }
127
128         for (spline = masklay->splines.first; spline; spline = spline->next) {
129                 ED_mask_spline_select_set(spline, do_select);
130         }
131 }
132
133 void ED_mask_select_toggle_all(Mask *mask, int action)
134 {
135         MaskLayer *masklay;
136
137         if (action == SEL_TOGGLE) {
138                 if (ED_mask_select_check(mask))
139                         action = SEL_DESELECT;
140                 else
141                         action = SEL_SELECT;
142         }
143
144         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
145
146                 if (masklay->restrictflag & MASK_RESTRICT_VIEW) {
147                         continue;
148                 }
149
150                 if (action == SEL_INVERT) {
151                         /* we don't have generic functons for this, its restricted to this operator
152                          * if one day we need to re-use such functionality, they can be split out */
153
154                         MaskSpline *spline;
155                         if (masklay->restrictflag & MASK_RESTRICT_SELECT) {
156                                 continue;
157                         }
158                         for (spline = masklay->splines.first; spline; spline = spline->next) {
159                                 int i;
160                                 for (i = 0; i < spline->tot_point; i++) {
161                                         MaskSplinePoint *point = &spline->points[i];
162                                         BKE_mask_point_select_set(point, !MASKPOINT_ISSEL_ANY(point));
163                                 }
164                         }
165
166                 }
167                 else {
168                         ED_mask_layer_select_set(masklay, (action == SEL_SELECT) ? TRUE : FALSE);
169                 }
170         }
171 }
172
173 void ED_mask_select_flush_all(Mask *mask)
174 {
175         MaskLayer *masklay;
176
177         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
178                 MaskSpline *spline;
179
180                 for (spline = masklay->splines.first; spline; spline = spline->next) {
181                         int i;
182
183                         spline->flag &= ~SELECT;
184
185                         /* intentionally _dont_ do this in the masklay loop
186                          * so we clear flags on all splines */
187                         if (masklay->restrictflag & MASK_RESTRICT_VIEW) {
188                                 continue;
189                         }
190
191                         for (i = 0; i < spline->tot_point; i++) {
192                                 MaskSplinePoint *cur_point = &spline->points[i];
193
194                                 if (MASKPOINT_ISSEL_ANY(cur_point)) {
195                                         spline->flag |= SELECT;
196                                 }
197                                 else {
198                                         int j;
199
200                                         for (j = 0; j < cur_point->tot_uw; j++) {
201                                                 if (cur_point->uw[j].flag & SELECT) {
202                                                         spline->flag |= SELECT;
203                                                         break;
204                                                 }
205                                         }
206                                 }
207                         }
208                 }
209         }
210 }
211
212 /******************** toggle selection *********************/
213
214 static int select_all_exec(bContext *C, wmOperator *op)
215 {
216         Mask *mask = CTX_data_edit_mask(C);
217         int action = RNA_enum_get(op->ptr, "action");
218
219         ED_mask_select_toggle_all(mask, action);
220         ED_mask_select_flush_all(mask);
221
222         WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
223
224         return OPERATOR_FINISHED;
225 }
226
227 void MASK_OT_select_all(wmOperatorType *ot)
228 {
229         /* identifiers */
230         ot->name = "(De)select All";
231         ot->description = "Change selection of all curve points";
232         ot->idname = "MASK_OT_select_all";
233
234         /* api callbacks */
235         ot->exec = select_all_exec;
236         ot->poll = ED_maskedit_mask_poll;
237
238         /* flags */
239         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
240
241         /* properties */
242         WM_operator_properties_select_all(ot);
243 }
244
245 /******************** select *********************/
246
247 static int select_exec(bContext *C, wmOperator *op)
248 {
249         Mask *mask = CTX_data_edit_mask(C);
250         MaskLayer *masklay;
251         MaskSpline *spline;
252         MaskSplinePoint *point = NULL;
253         float co[2];
254         short extend = RNA_boolean_get(op->ptr, "extend");
255         short deselect = RNA_boolean_get(op->ptr, "deselect");
256         short toggle = RNA_boolean_get(op->ptr, "toggle");
257
258         int is_handle = 0;
259         const float threshold = 19;
260
261         RNA_float_get_array(op->ptr, "location", co);
262
263         point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, &is_handle, NULL);
264
265         if (extend == 0 && deselect == 0 && toggle == 0)
266                 ED_mask_select_toggle_all(mask, SEL_DESELECT);
267
268         if (point) {
269
270                 if (is_handle) {
271                         if (extend) {
272                                 masklay->act_spline = spline;
273                                 masklay->act_point = point;
274
275                                 BKE_mask_point_select_set_handle(point, TRUE);
276                         }
277                         else if (deselect) {
278                                 BKE_mask_point_select_set_handle(point, FALSE);
279                         }
280                         else {
281                                 masklay->act_spline = spline;
282                                 masklay->act_point = point;
283
284                                 if (!MASKPOINT_ISSEL_HANDLE(point)) {
285                                         BKE_mask_point_select_set_handle(point, TRUE);
286                                 }
287                                 else if (toggle) {
288                                         BKE_mask_point_select_set_handle(point, FALSE);
289                                 }
290                         }
291                 }
292                 else {
293                         if (extend) {
294                                 masklay->act_spline = spline;
295                                 masklay->act_point = point;
296
297                                 BKE_mask_point_select_set(point, TRUE);
298                         }
299                         else if (deselect) {
300                                 BKE_mask_point_select_set(point, FALSE);
301                         }
302                         else {
303                                 masklay->act_spline = spline;
304                                 masklay->act_point = point;
305
306                                 if (!MASKPOINT_ISSEL_ANY(point)) {
307                                         BKE_mask_point_select_set(point, TRUE);
308                                 }
309                                 else if (toggle) {
310                                         BKE_mask_point_select_set(point, FALSE);
311                                 }
312                         }
313                 }
314
315                 masklay->act_spline = spline;
316                 masklay->act_point = point;
317
318                 ED_mask_select_flush_all(mask);
319
320                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
321
322                 return OPERATOR_FINISHED;
323         }
324         else {
325                 MaskSplinePointUW *uw;
326
327                 if (ED_mask_feather_find_nearest(C, mask, co, threshold, &masklay, &spline, &point, &uw, NULL)) {
328
329                         if (extend) {
330                                 masklay->act_spline = spline;
331                                 masklay->act_point = point;
332
333                                 if (uw) uw->flag |= SELECT;
334                         }
335                         else if (deselect) {
336                                 if (uw) uw->flag &= ~SELECT;
337                         }
338                         else {
339                                 masklay->act_spline = spline;
340                                 masklay->act_point = point;
341
342                                 if (uw) {
343                                         if (!(uw->flag & SELECT)) {
344                                                 uw->flag |= SELECT;
345                                         }
346                                         else if (toggle) {
347                                                 uw->flag &= ~SELECT;
348                                         }
349                                 }
350                         }
351
352                         ED_mask_select_flush_all(mask);
353
354                         WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
355
356                         return OPERATOR_FINISHED;
357                 }
358         }
359
360         return OPERATOR_PASS_THROUGH;
361 }
362
363 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
364 {
365         ScrArea *sa = CTX_wm_area(C);
366         ARegion *ar = CTX_wm_region(C);
367
368         float co[2];
369
370         ED_mask_mouse_pos(sa, ar, event->mval, co);
371
372         RNA_float_set_array(op->ptr, "location", co);
373
374         return select_exec(C, op);
375 }
376
377 void MASK_OT_select(wmOperatorType *ot)
378 {
379         /* identifiers */
380         ot->name = "Select";
381         ot->description = "Select spline points";
382         ot->idname = "MASK_OT_select";
383
384         /* api callbacks */
385         ot->exec = select_exec;
386         ot->invoke = select_invoke;
387         ot->poll = ED_maskedit_mask_poll;
388
389         /* flags */
390         ot->flag = OPTYPE_UNDO;
391
392         /* properties */
393         WM_operator_properties_mouse_select(ot);
394
395         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MIN, FLT_MAX,
396                              "Location", "Location of vertex in normalized space", -1.0f, 1.0f);
397 }
398
399
400
401 /********************** border select operator *********************/
402
403 static int border_select_exec(bContext *C, wmOperator *op)
404 {
405         ScrArea *sa = CTX_wm_area(C);
406         ARegion *ar = CTX_wm_region(C);
407
408         Mask *mask = CTX_data_edit_mask(C);
409         MaskLayer *masklay;
410         int i;
411
412         rcti rect;
413         rctf rectf;
414         int change = FALSE, mode, extend;
415
416         /* get rectangle from operator */
417         rect.xmin = RNA_int_get(op->ptr, "xmin");
418         rect.ymin = RNA_int_get(op->ptr, "ymin");
419         rect.xmax = RNA_int_get(op->ptr, "xmax");
420         rect.ymax = RNA_int_get(op->ptr, "ymax");
421
422         ED_mask_point_pos(sa, ar, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
423         ED_mask_point_pos(sa, ar, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
424
425         mode = RNA_int_get(op->ptr, "gesture_mode");
426         extend = RNA_boolean_get(op->ptr, "extend");
427
428         /* do actual selection */
429         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
430                 MaskSpline *spline;
431
432                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
433                         continue;
434                 }
435
436                 for (spline = masklay->splines.first; spline; spline = spline->next) {
437                         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
438
439                         for (i = 0; i < spline->tot_point; i++) {
440                                 MaskSplinePoint *point = &spline->points[i];
441                                 MaskSplinePoint *point_deform = &points_array[i];
442
443                                 /* TODO: handles? */
444                                 /* TODO: uw? */
445
446                                 if (BLI_in_rctf_v(&rectf, point_deform->bezt.vec[1])) {
447                                         BKE_mask_point_select_set(point, mode == GESTURE_MODAL_SELECT);
448                                         BKE_mask_point_select_set_handle(point, mode == GESTURE_MODAL_SELECT);
449                                 }
450                                 else if (!extend) {
451                                         BKE_mask_point_select_set(point, FALSE);
452                                         BKE_mask_point_select_set_handle(point, FALSE);
453                                 }
454
455                                 change = TRUE;
456                         }
457                 }
458         }
459
460         if (change) {
461                 ED_mask_select_flush_all(mask);
462
463                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
464
465                 return OPERATOR_FINISHED;
466         }
467
468         return OPERATOR_CANCELLED;
469 }
470
471 void MASK_OT_select_border(wmOperatorType *ot)
472 {
473         /* identifiers */
474         ot->name = "Border Select";
475         ot->description = "Select markers using border selection";
476         ot->idname = "MASK_OT_select_border";
477
478         /* api callbacks */
479         ot->invoke = WM_border_select_invoke;
480         ot->exec = border_select_exec;
481         ot->modal = WM_border_select_modal;
482         ot->poll = ED_maskedit_mask_poll;
483
484         /* flags */
485         ot->flag = OPTYPE_UNDO;
486
487         /* properties */
488         WM_operator_properties_gesture_border(ot, TRUE);
489 }
490
491 static int do_lasso_select_mask(bContext *C, int mcords[][2], short moves, short select)
492 {
493         ScrArea *sa = CTX_wm_area(C);
494         ARegion *ar = CTX_wm_region(C);
495
496         Mask *mask = CTX_data_edit_mask(C);
497         MaskLayer *masklay;
498         int i;
499
500         rcti rect;
501         int change = FALSE;
502
503         /* get rectangle from operator */
504         BLI_lasso_boundbox(&rect, mcords, moves);
505
506         /* do actual selection */
507         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
508                 MaskSpline *spline;
509
510                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
511                         continue;
512                 }
513
514                 for (spline = masklay->splines.first; spline; spline = spline->next) {
515                         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
516
517                         for (i = 0; i < spline->tot_point; i++) {
518                                 MaskSplinePoint *point = &spline->points[i];
519                                 MaskSplinePoint *point_deform = &points_array[i];
520
521                                 /* TODO: handles? */
522                                 /* TODO: uw? */
523
524                                 float screen_co[2];
525
526                                 /* marker in screen coords */
527                                 ED_mask_point_pos__reverse(sa, ar,
528                                                            point_deform->bezt.vec[1][0], point_deform->bezt.vec[1][1],
529                                                            &screen_co[0], &screen_co[1]);
530
531                                 if (BLI_in_rcti(&rect, screen_co[0], screen_co[1]) &&
532                                     BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX))
533                                 {
534                                         BKE_mask_point_select_set(point, select);
535                                         BKE_mask_point_select_set_handle(point, select);
536                                 }
537
538                                 change = TRUE;
539                         }
540                 }
541         }
542
543         if (change) {
544                 ED_mask_select_flush_all(mask);
545
546                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
547         }
548
549         return change;
550 }
551
552 static int clip_lasso_select_exec(bContext *C, wmOperator *op)
553 {
554         int mcords_tot;
555         int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
556
557         if (mcords) {
558                 short select;
559
560                 select = !RNA_boolean_get(op->ptr, "deselect");
561                 do_lasso_select_mask(C, mcords, mcords_tot, select);
562
563                 MEM_freeN(mcords);
564
565                 return OPERATOR_FINISHED;
566         }
567         return OPERATOR_PASS_THROUGH;
568 }
569
570 void MASK_OT_select_lasso(wmOperatorType *ot)
571 {
572         /* identifiers */
573         ot->name = "Lasso Select";
574         ot->description = "Select markers using lasso selection";
575         ot->idname = "MASK_OT_select_lasso";
576
577         /* api callbacks */
578         ot->invoke = WM_gesture_lasso_invoke;
579         ot->modal = WM_gesture_lasso_modal;
580         ot->exec = clip_lasso_select_exec;
581         ot->poll = ED_maskedit_mask_poll;
582         ot->cancel = WM_gesture_lasso_cancel;
583
584         /* flags */
585         ot->flag = OPTYPE_UNDO;
586
587         /* properties */
588         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
589         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items");
590         RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection instead of deselecting everything first");
591 }
592
593 /********************** circle select operator *********************/
594
595 static int mask_spline_point_inside_ellipse(BezTriple *bezt, float offset[2], float ellipse[2])
596 {
597         /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
598         float x, y;
599
600         x = (bezt->vec[1][0] - offset[0]) * ellipse[0];
601         y = (bezt->vec[1][1] - offset[1]) * ellipse[1];
602
603         return x * x + y * y < 1.0f;
604 }
605
606 static int circle_select_exec(bContext *C, wmOperator *op)
607 {
608         ScrArea *sa = CTX_wm_area(C);
609         ARegion *ar = CTX_wm_region(C);
610
611         Mask *mask = CTX_data_edit_mask(C);
612         MaskLayer *masklay;
613         int i;
614
615         int x, y, radius, width, height, mode, change = FALSE;
616         float zoomx, zoomy, offset[2], ellipse[2];
617
618         /* get operator properties */
619         x = RNA_int_get(op->ptr, "x");
620         y = RNA_int_get(op->ptr, "y");
621         radius = RNA_int_get(op->ptr, "radius");
622
623         mode = RNA_int_get(op->ptr, "gesture_mode");
624
625         /* compute ellipse and position in unified coordinates */
626         ED_mask_get_size(sa, &width, &height);
627         ED_mask_zoom(sa, ar, &zoomx, &zoomy);
628         width = height = MAX2(width, height);
629
630         ellipse[0] = width * zoomx / radius;
631         ellipse[1] = height * zoomy / radius;
632
633         ED_mask_point_pos(sa, ar, x, y, &offset[0], &offset[1]);
634
635         /* do actual selection */
636         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
637                 MaskSpline *spline;
638
639                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
640                         continue;
641                 }
642
643                 for (spline = masklay->splines.first; spline; spline = spline->next) {
644                         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
645
646                         for (i = 0; i < spline->tot_point; i++) {
647                                 MaskSplinePoint *point = &spline->points[i];
648                                 MaskSplinePoint *point_deform = &points_array[i];
649
650                                 if (mask_spline_point_inside_ellipse(&point_deform->bezt, offset, ellipse)) {
651                                         BKE_mask_point_select_set(point, mode == GESTURE_MODAL_SELECT);
652                                         BKE_mask_point_select_set_handle(point, mode == GESTURE_MODAL_SELECT);
653
654                                         change = TRUE;
655                                 }
656                         }
657                 }
658         }
659
660         if (change) {
661                 ED_mask_select_flush_all(mask);
662
663                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
664
665                 return OPERATOR_FINISHED;
666         }
667
668         return OPERATOR_CANCELLED;
669 }
670
671 void MASK_OT_select_circle(wmOperatorType *ot)
672 {
673         /* identifiers */
674         ot->name = "Circle Select";
675         ot->description = "Select markers using circle selection";
676         ot->idname = "MASK_OT_select_circle";
677
678         /* api callbacks */
679         ot->invoke = WM_gesture_circle_invoke;
680         ot->modal = WM_gesture_circle_modal;
681         ot->exec = circle_select_exec;
682         ot->poll = ED_maskedit_mask_poll;
683
684         /* flags */
685         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
686
687         /* properties */
688         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
689         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
690         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
691         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
692 }
693
694 static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
695 {
696         ScrArea *sa = CTX_wm_area(C);
697         ARegion *ar = CTX_wm_region(C);
698
699         Mask *mask = CTX_data_edit_mask(C);
700         MaskLayer *masklay;
701         MaskSpline *spline;
702         MaskSplinePoint *point = NULL;
703         float co[2];
704         int do_select = !RNA_boolean_get(op->ptr, "deselect");
705
706         int is_handle = 0;
707         const float threshold = 19;
708         int change = FALSE;
709
710         ED_mask_mouse_pos(sa, ar, event->mval, co);
711
712         point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, &is_handle, NULL);
713
714         if (point) {
715                 ED_mask_spline_select_set(spline, do_select);
716                 masklay->act_spline = spline;
717                 masklay->act_point = point;
718
719                 change = TRUE;
720         }
721
722         if (change) {
723                 ED_mask_select_flush_all(mask);
724
725                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
726
727                 return OPERATOR_FINISHED;
728         }
729
730         return OPERATOR_CANCELLED;
731 }
732
733 void MASK_OT_select_linked_pick(wmOperatorType *ot)
734 {
735         /* identifiers */
736         ot->name = "Select Linked";
737         ot->idname = "MASK_OT_select_linked_pick";
738         ot->description = "(De)select all points linked to the curve under the mouse cursor";
739
740         /* api callbacks */
741         ot->invoke = mask_select_linked_pick_invoke;
742         ot->poll = ED_maskedit_mask_poll;
743
744         /* flags */
745         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
746
747         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
748 }
749
750 static int mask_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
751 {
752         Mask *mask = CTX_data_edit_mask(C);
753         MaskLayer *masklay;
754
755         int change = FALSE;
756
757         /* do actual selection */
758         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
759                 MaskSpline *spline;
760
761                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
762                         continue;
763                 }
764
765                 for (spline = masklay->splines.first; spline; spline = spline->next) {
766                         if (ED_mask_spline_select_check(spline)) {
767                                 ED_mask_spline_select_set(spline, TRUE);
768                                 change = TRUE;
769                         }
770                 }
771         }
772
773         if (change) {
774                 ED_mask_select_flush_all(mask);
775
776                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
777
778                 return OPERATOR_FINISHED;
779         }
780
781         return OPERATOR_CANCELLED;
782 }
783
784 void MASK_OT_select_linked(wmOperatorType *ot)
785 {
786         /* identifiers */
787         ot->name = "Select Linked All";
788         ot->idname = "MASK_OT_select_linked";
789         ot->description = "Select all vertices linked to the active mesh";
790
791         /* api callbacks */
792         ot->exec = mask_select_linked_exec;
793         ot->poll = ED_maskedit_mask_poll;
794
795         /* flags */
796         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
797 }