Changes in clip editor's public api to make it's more clear
[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                 ED_mask_layer_select_set(masklay, (action == SEL_SELECT) ? TRUE : FALSE);
151         }
152 }
153
154 void ED_mask_select_flush_all(Mask *mask)
155 {
156         MaskLayer *masklay;
157
158         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
159                 MaskSpline *spline;
160
161                 for (spline = masklay->splines.first; spline; spline = spline->next) {
162                         int i;
163
164                         spline->flag &= ~SELECT;
165
166                         /* intentionally _dont_ do this in the masklay loop
167                          * so we clear flags on all splines */
168                         if (masklay->restrictflag & MASK_RESTRICT_VIEW) {
169                                 continue;
170                         }
171
172                         for (i = 0; i < spline->tot_point; i++) {
173                                 MaskSplinePoint *cur_point = &spline->points[i];
174
175                                 if (MASKPOINT_ISSEL_ANY(cur_point)) {
176                                         spline->flag |= SELECT;
177                                 }
178                                 else {
179                                         int j;
180
181                                         for (j = 0; j < cur_point->tot_uw; j++) {
182                                                 if (cur_point->uw[j].flag & SELECT) {
183                                                         spline->flag |= SELECT;
184                                                         break;
185                                                 }
186                                         }
187                                 }
188                         }
189                 }
190         }
191 }
192
193 /******************** toggle selection *********************/
194
195 static int select_all_exec(bContext *C, wmOperator *op)
196 {
197         Mask *mask = CTX_data_edit_mask(C);
198         int action = RNA_enum_get(op->ptr, "action");
199
200         ED_mask_select_toggle_all(mask, action);
201         ED_mask_select_flush_all(mask);
202
203         WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
204
205         return OPERATOR_FINISHED;
206 }
207
208 void MASK_OT_select_all(wmOperatorType *ot)
209 {
210         /* identifiers */
211         ot->name = "(De)select All";
212         ot->description = "Change selection of all curve points";
213         ot->idname = "MASK_OT_select_all";
214
215         /* api callbacks */
216         ot->exec = select_all_exec;
217         ot->poll = ED_maskedit_mask_poll;
218
219         /* flags */
220         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
221
222         /* properties */
223         WM_operator_properties_select_all(ot);
224 }
225
226 /******************** select *********************/
227
228 static int select_exec(bContext *C, wmOperator *op)
229 {
230         Mask *mask = CTX_data_edit_mask(C);
231         MaskLayer *masklay;
232         MaskSpline *spline;
233         MaskSplinePoint *point = NULL;
234         float co[2];
235         short extend = RNA_boolean_get(op->ptr, "extend");
236         short deselect = RNA_boolean_get(op->ptr, "deselect");
237         short toggle = RNA_boolean_get(op->ptr, "toggle");
238
239         int is_handle = 0;
240         const float threshold = 19;
241
242         RNA_float_get_array(op->ptr, "location", co);
243
244         point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, &is_handle, NULL);
245
246         if (extend == 0 && deselect == 0 && toggle == 0)
247                 ED_mask_select_toggle_all(mask, SEL_DESELECT);
248
249         if (point) {
250
251                 if (is_handle) {
252                         if (extend) {
253                                 masklay->act_spline = spline;
254                                 masklay->act_point = point;
255
256                                 BKE_mask_point_select_set_handle(point, TRUE);
257                         }
258                         else if (deselect) {
259                                 BKE_mask_point_select_set_handle(point, FALSE);
260                         }
261                         else {
262                                 masklay->act_spline = spline;
263                                 masklay->act_point = point;
264
265                                 if (!MASKPOINT_ISSEL_HANDLE(point)) {
266                                         BKE_mask_point_select_set_handle(point, TRUE);
267                                 }
268                                 else if (toggle) {
269                                         BKE_mask_point_select_set_handle(point, FALSE);
270                                 }
271                         }
272                 }
273                 else {
274                         if (extend) {
275                                 masklay->act_spline = spline;
276                                 masklay->act_point = point;
277
278                                 BKE_mask_point_select_set(point, TRUE);
279                         }
280                         else if (deselect) {
281                                 BKE_mask_point_select_set(point, FALSE);
282                         }
283                         else {
284                                 masklay->act_spline = spline;
285                                 masklay->act_point = point;
286
287                                 if (!MASKPOINT_ISSEL_ANY(point)) {
288                                         BKE_mask_point_select_set(point, TRUE);
289                                 }
290                                 else if (toggle) {
291                                         BKE_mask_point_select_set(point, FALSE);
292                                 }
293                         }
294                 }
295
296                 masklay->act_spline = spline;
297                 masklay->act_point = point;
298
299                 ED_mask_select_flush_all(mask);
300
301                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
302
303                 return OPERATOR_FINISHED;
304         }
305         else {
306                 MaskSplinePointUW *uw;
307
308                 if (ED_mask_feather_find_nearest(C, mask, co, threshold, &masklay, &spline, &point, &uw, NULL)) {
309
310                         if (extend) {
311                                 masklay->act_spline = spline;
312                                 masklay->act_point = point;
313
314                                 if (uw) uw->flag |= SELECT;
315                         }
316                         else if (deselect) {
317                                 if (uw) uw->flag &= ~SELECT;
318                         }
319                         else {
320                                 masklay->act_spline = spline;
321                                 masklay->act_point = point;
322
323                                 if (uw) {
324                                         if (!(uw->flag & SELECT)) {
325                                                 uw->flag |= SELECT;
326                                         }
327                                         else if (toggle) {
328                                                 uw->flag &= ~SELECT;
329                                         }
330                                 }
331                         }
332
333                         ED_mask_select_flush_all(mask);
334
335                         WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
336
337                         return OPERATOR_FINISHED;
338                 }
339         }
340
341         return OPERATOR_PASS_THROUGH;
342 }
343
344 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
345 {
346         float co[2];
347
348         ED_mask_mouse_pos(C, event, co);
349
350         RNA_float_set_array(op->ptr, "location", co);
351
352         return select_exec(C, op);
353 }
354
355 void MASK_OT_select(wmOperatorType *ot)
356 {
357         /* identifiers */
358         ot->name = "Select";
359         ot->description = "Select spline points";
360         ot->idname = "MASK_OT_select";
361
362         /* api callbacks */
363         ot->exec = select_exec;
364         ot->invoke = select_invoke;
365         ot->poll = ED_maskedit_mask_poll;
366
367         /* flags */
368         ot->flag = OPTYPE_UNDO;
369
370         /* properties */
371         WM_operator_properties_mouse_select(ot);
372
373         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MIN, FLT_MAX,
374                              "Location", "Location of vertex in normalized space", -1.0f, 1.0f);
375 }
376
377
378
379 /********************** border select operator *********************/
380
381 static int border_select_exec(bContext *C, wmOperator *op)
382 {
383         Mask *mask = CTX_data_edit_mask(C);
384         MaskLayer *masklay;
385         int i;
386
387         rcti rect;
388         rctf rectf;
389         int change = FALSE, mode, extend;
390
391         /* get rectangle from operator */
392         rect.xmin = RNA_int_get(op->ptr, "xmin");
393         rect.ymin = RNA_int_get(op->ptr, "ymin");
394         rect.xmax = RNA_int_get(op->ptr, "xmax");
395         rect.ymax = RNA_int_get(op->ptr, "ymax");
396
397         ED_mask_point_pos(C, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
398         ED_mask_point_pos(C, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
399
400         mode = RNA_int_get(op->ptr, "gesture_mode");
401         extend = RNA_boolean_get(op->ptr, "extend");
402
403         /* do actual selection */
404         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
405                 MaskSpline *spline;
406
407                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
408                         continue;
409                 }
410
411                 for (spline = masklay->splines.first; spline; spline = spline->next) {
412                         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
413
414                         for (i = 0; i < spline->tot_point; i++) {
415                                 MaskSplinePoint *point = &spline->points[i];
416                                 MaskSplinePoint *point_deform = &points_array[i];
417
418                                 /* TODO: handles? */
419                                 /* TODO: uw? */
420
421                                 if (BLI_in_rctf(&rectf, point_deform->bezt.vec[1][0], point_deform->bezt.vec[1][1])) {
422                                         BKE_mask_point_select_set(point, mode == GESTURE_MODAL_SELECT);
423                                         BKE_mask_point_select_set_handle(point, mode == GESTURE_MODAL_SELECT);
424                                 }
425                                 else if (!extend) {
426                                         BKE_mask_point_select_set(point, FALSE);
427                                         BKE_mask_point_select_set_handle(point, FALSE);
428                                 }
429
430                                 change = TRUE;
431                         }
432                 }
433         }
434
435         if (change) {
436                 ED_mask_select_flush_all(mask);
437
438                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
439
440                 return OPERATOR_FINISHED;
441         }
442
443         return OPERATOR_CANCELLED;
444 }
445
446 void MASK_OT_select_border(wmOperatorType *ot)
447 {
448         /* identifiers */
449         ot->name = "Border Select";
450         ot->description = "Select markers using border selection";
451         ot->idname = "MASK_OT_select_border";
452
453         /* api callbacks */
454         ot->invoke = WM_border_select_invoke;
455         ot->exec = border_select_exec;
456         ot->modal = WM_border_select_modal;
457         ot->poll = ED_maskedit_mask_poll;
458
459         /* flags */
460         ot->flag = OPTYPE_UNDO;
461
462         /* properties */
463         WM_operator_properties_gesture_border(ot, TRUE);
464 }
465
466 static int do_lasso_select_mask(bContext *C, int mcords[][2], short moves, short select)
467 {
468         Mask *mask = CTX_data_edit_mask(C);
469         MaskLayer *masklay;
470         int i;
471
472         rcti rect;
473         int change = FALSE;
474
475         /* get rectangle from operator */
476         BLI_lasso_boundbox(&rect, mcords, moves);
477
478         /* do actual selection */
479         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
480                 MaskSpline *spline;
481
482                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
483                         continue;
484                 }
485
486                 for (spline = masklay->splines.first; spline; spline = spline->next) {
487                         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
488
489                         for (i = 0; i < spline->tot_point; i++) {
490                                 MaskSplinePoint *point = &spline->points[i];
491                                 MaskSplinePoint *point_deform = &points_array[i];
492
493                                 /* TODO: handles? */
494                                 /* TODO: uw? */
495
496                                 float screen_co[2];
497
498                                 /* marker in screen coords */
499                                 ED_mask_point_pos__reverse(C,
500                                                            point_deform->bezt.vec[1][0], point_deform->bezt.vec[1][1],
501                                                            &screen_co[0], &screen_co[1]);
502
503                                 if (BLI_in_rcti(&rect, screen_co[0], screen_co[1]) &&
504                                     BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX))
505                                 {
506                                         BKE_mask_point_select_set(point, select);
507                                         BKE_mask_point_select_set_handle(point, select);
508                                 }
509
510                                 change = TRUE;
511                         }
512                 }
513         }
514
515         if (change) {
516                 ED_mask_select_flush_all(mask);
517
518                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
519         }
520
521         return change;
522 }
523
524 static int clip_lasso_select_exec(bContext *C, wmOperator *op)
525 {
526         int mcords_tot;
527         int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
528
529         if (mcords) {
530                 short select;
531
532                 select = !RNA_boolean_get(op->ptr, "deselect");
533                 do_lasso_select_mask(C, mcords, mcords_tot, select);
534
535                 MEM_freeN(mcords);
536
537                 return OPERATOR_FINISHED;
538         }
539         return OPERATOR_PASS_THROUGH;
540 }
541
542 void MASK_OT_select_lasso(wmOperatorType *ot)
543 {
544         /* identifiers */
545         ot->name = "Lasso Select";
546         ot->description = "Select markers using lasso selection";
547         ot->idname = "MASK_OT_select_lasso";
548
549         /* api callbacks */
550         ot->invoke = WM_gesture_lasso_invoke;
551         ot->modal = WM_gesture_lasso_modal;
552         ot->exec = clip_lasso_select_exec;
553         ot->poll = ED_maskedit_mask_poll;
554         ot->cancel = WM_gesture_lasso_cancel;
555
556         /* flags */
557         ot->flag = OPTYPE_UNDO;
558
559         /* properties */
560         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
561         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items");
562         RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection instead of deselecting everything first");
563 }
564
565 /********************** circle select operator *********************/
566
567 static int mask_spline_point_inside_ellipse(BezTriple *bezt, float offset[2], float ellipse[2])
568 {
569         /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
570         float x, y;
571
572         x = (bezt->vec[1][0] - offset[0]) * ellipse[0];
573         y = (bezt->vec[1][1] - offset[1]) * ellipse[1];
574
575         return x * x + y * y < 1.0f;
576 }
577
578 static int circle_select_exec(bContext *C, wmOperator *op)
579 {
580         Mask *mask = CTX_data_edit_mask(C);
581         MaskLayer *masklay;
582         int i;
583
584         SpaceClip *sc = CTX_wm_space_clip(C);
585         ARegion *ar = CTX_wm_region(C);
586         int x, y, radius, width, height, mode, change = FALSE;
587         float zoomx, zoomy, offset[2], ellipse[2];
588
589         /* get operator properties */
590         x = RNA_int_get(op->ptr, "x");
591         y = RNA_int_get(op->ptr, "y");
592         radius = RNA_int_get(op->ptr, "radius");
593
594         mode = RNA_int_get(op->ptr, "gesture_mode");
595
596         /* TODO - make generic! - this is SpaceClip only! */
597         /* compute ellipse and position in unified coordinates */
598         ED_space_clip_get_clip_size(sc, &width, &height);
599         ED_space_clip_get_zoom(sc, ar, &zoomx, &zoomy);
600         width = height = MAX2(width, height);
601
602         ellipse[0] = width * zoomx / radius;
603         ellipse[1] = height * zoomy / radius;
604
605         ED_mask_point_pos(C, x, y, &offset[0], &offset[1]);
606
607         /* do actual selection */
608         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
609                 MaskSpline *spline;
610
611                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
612                         continue;
613                 }
614
615                 for (spline = masklay->splines.first; spline; spline = spline->next) {
616                         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
617
618                         for (i = 0; i < spline->tot_point; i++) {
619                                 MaskSplinePoint *point = &spline->points[i];
620                                 MaskSplinePoint *point_deform = &points_array[i];
621
622                                 if (mask_spline_point_inside_ellipse(&point_deform->bezt, offset, ellipse)) {
623                                         BKE_mask_point_select_set(point, mode == GESTURE_MODAL_SELECT);
624                                         BKE_mask_point_select_set_handle(point, mode == GESTURE_MODAL_SELECT);
625
626                                         change = TRUE;
627                                 }
628                         }
629                 }
630         }
631
632         if (change) {
633                 ED_mask_select_flush_all(mask);
634
635                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
636
637                 return OPERATOR_FINISHED;
638         }
639
640         return OPERATOR_CANCELLED;
641 }
642
643 void MASK_OT_select_circle(wmOperatorType *ot)
644 {
645         /* identifiers */
646         ot->name = "Circle Select";
647         ot->description = "Select markers using circle selection";
648         ot->idname = "MASK_OT_select_circle";
649
650         /* api callbacks */
651         ot->invoke = WM_gesture_circle_invoke;
652         ot->modal = WM_gesture_circle_modal;
653         ot->exec = circle_select_exec;
654         ot->poll = ED_maskedit_mask_poll;
655
656         /* flags */
657         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
658
659         /* properties */
660         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
661         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
662         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
663         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
664 }
665
666 static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
667 {
668         Mask *mask = CTX_data_edit_mask(C);
669         MaskLayer *masklay;
670         MaskSpline *spline;
671         MaskSplinePoint *point = NULL;
672         float co[2];
673         int do_select = !RNA_boolean_get(op->ptr, "deselect");
674
675         int is_handle = 0;
676         const float threshold = 19;
677         int change = FALSE;
678
679         ED_mask_mouse_pos(C, event, co);
680
681         point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, &is_handle, NULL);
682
683         if (point) {
684                 ED_mask_spline_select_set(spline, do_select);
685                 masklay->act_spline = spline;
686                 masklay->act_point = point;
687
688                 change = TRUE;
689         }
690
691         if (change) {
692                 ED_mask_select_flush_all(mask);
693
694                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
695
696                 return OPERATOR_FINISHED;
697         }
698
699         return OPERATOR_CANCELLED;
700 }
701
702 void MASK_OT_select_linked_pick(wmOperatorType *ot)
703 {
704         /* identifiers */
705         ot->name = "Select Linked";
706         ot->idname = "MASK_OT_select_linked_pick";
707         ot->description = "(De)select all points linked to the curve under the mouse cursor";
708
709         /* api callbacks */
710         ot->invoke = mask_select_linked_pick_invoke;
711         ot->poll = ED_maskedit_mask_poll;
712
713         /* flags */
714         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
715
716         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
717 }
718
719 static int mask_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
720 {
721         Mask *mask = CTX_data_edit_mask(C);
722         MaskLayer *masklay;
723
724         int change = FALSE;
725
726         /* do actual selection */
727         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
728                 MaskSpline *spline;
729
730                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
731                         continue;
732                 }
733
734                 for (spline = masklay->splines.first; spline; spline = spline->next) {
735                         if (ED_mask_spline_select_check(spline)) {
736                                 ED_mask_spline_select_set(spline, TRUE);
737                                 change = TRUE;
738                         }
739                 }
740         }
741
742         if (change) {
743                 ED_mask_select_flush_all(mask);
744
745                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
746
747                 return OPERATOR_FINISHED;
748         }
749
750         return OPERATOR_CANCELLED;
751 }
752
753 void MASK_OT_select_linked(wmOperatorType *ot)
754 {
755         /* identifiers */
756         ot->name = "Select Linked All";
757         ot->idname = "MASK_OT_select_linked";
758         ot->description = "Select all vertices linked to the active mesh";
759
760         /* api callbacks */
761         ot->exec = mask_select_linked_exec;
762         ot->poll = ED_maskedit_mask_poll;
763
764         /* flags */
765         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
766 }