81cfbb9b5866c55d7ee4b2b5739015c189b307dd
[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         ScrArea *sa = CTX_wm_area(C);
347         ARegion *ar = CTX_wm_region(C);
348
349         float co[2];
350
351         ED_mask_mouse_pos(sa, ar, event, co);
352
353         RNA_float_set_array(op->ptr, "location", co);
354
355         return select_exec(C, op);
356 }
357
358 void MASK_OT_select(wmOperatorType *ot)
359 {
360         /* identifiers */
361         ot->name = "Select";
362         ot->description = "Select spline points";
363         ot->idname = "MASK_OT_select";
364
365         /* api callbacks */
366         ot->exec = select_exec;
367         ot->invoke = select_invoke;
368         ot->poll = ED_maskedit_mask_poll;
369
370         /* flags */
371         ot->flag = OPTYPE_UNDO;
372
373         /* properties */
374         WM_operator_properties_mouse_select(ot);
375
376         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MIN, FLT_MAX,
377                              "Location", "Location of vertex in normalized space", -1.0f, 1.0f);
378 }
379
380
381
382 /********************** border select operator *********************/
383
384 static int border_select_exec(bContext *C, wmOperator *op)
385 {
386         ScrArea *sa = CTX_wm_area(C);
387         ARegion *ar = CTX_wm_region(C);
388
389         Mask *mask = CTX_data_edit_mask(C);
390         MaskLayer *masklay;
391         int i;
392
393         rcti rect;
394         rctf rectf;
395         int change = FALSE, mode, extend;
396
397         /* get rectangle from operator */
398         rect.xmin = RNA_int_get(op->ptr, "xmin");
399         rect.ymin = RNA_int_get(op->ptr, "ymin");
400         rect.xmax = RNA_int_get(op->ptr, "xmax");
401         rect.ymax = RNA_int_get(op->ptr, "ymax");
402
403         ED_mask_point_pos(sa, ar, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
404         ED_mask_point_pos(sa, ar, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
405
406         mode = RNA_int_get(op->ptr, "gesture_mode");
407         extend = RNA_boolean_get(op->ptr, "extend");
408
409         /* do actual selection */
410         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
411                 MaskSpline *spline;
412
413                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
414                         continue;
415                 }
416
417                 for (spline = masklay->splines.first; spline; spline = spline->next) {
418                         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
419
420                         for (i = 0; i < spline->tot_point; i++) {
421                                 MaskSplinePoint *point = &spline->points[i];
422                                 MaskSplinePoint *point_deform = &points_array[i];
423
424                                 /* TODO: handles? */
425                                 /* TODO: uw? */
426
427                                 if (BLI_in_rctf_v(&rectf, point_deform->bezt.vec[1])) {
428                                         BKE_mask_point_select_set(point, mode == GESTURE_MODAL_SELECT);
429                                         BKE_mask_point_select_set_handle(point, mode == GESTURE_MODAL_SELECT);
430                                 }
431                                 else if (!extend) {
432                                         BKE_mask_point_select_set(point, FALSE);
433                                         BKE_mask_point_select_set_handle(point, FALSE);
434                                 }
435
436                                 change = TRUE;
437                         }
438                 }
439         }
440
441         if (change) {
442                 ED_mask_select_flush_all(mask);
443
444                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
445
446                 return OPERATOR_FINISHED;
447         }
448
449         return OPERATOR_CANCELLED;
450 }
451
452 void MASK_OT_select_border(wmOperatorType *ot)
453 {
454         /* identifiers */
455         ot->name = "Border Select";
456         ot->description = "Select markers using border selection";
457         ot->idname = "MASK_OT_select_border";
458
459         /* api callbacks */
460         ot->invoke = WM_border_select_invoke;
461         ot->exec = border_select_exec;
462         ot->modal = WM_border_select_modal;
463         ot->poll = ED_maskedit_mask_poll;
464
465         /* flags */
466         ot->flag = OPTYPE_UNDO;
467
468         /* properties */
469         WM_operator_properties_gesture_border(ot, TRUE);
470 }
471
472 static int do_lasso_select_mask(bContext *C, int mcords[][2], short moves, short select)
473 {
474         ScrArea *sa = CTX_wm_area(C);
475         ARegion *ar = CTX_wm_region(C);
476
477         Mask *mask = CTX_data_edit_mask(C);
478         MaskLayer *masklay;
479         int i;
480
481         rcti rect;
482         int change = FALSE;
483
484         /* get rectangle from operator */
485         BLI_lasso_boundbox(&rect, mcords, moves);
486
487         /* do actual selection */
488         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
489                 MaskSpline *spline;
490
491                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
492                         continue;
493                 }
494
495                 for (spline = masklay->splines.first; spline; spline = spline->next) {
496                         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
497
498                         for (i = 0; i < spline->tot_point; i++) {
499                                 MaskSplinePoint *point = &spline->points[i];
500                                 MaskSplinePoint *point_deform = &points_array[i];
501
502                                 /* TODO: handles? */
503                                 /* TODO: uw? */
504
505                                 float screen_co[2];
506
507                                 /* marker in screen coords */
508                                 ED_mask_point_pos__reverse(sa, ar,
509                                                            point_deform->bezt.vec[1][0], point_deform->bezt.vec[1][1],
510                                                            &screen_co[0], &screen_co[1]);
511
512                                 if (BLI_in_rcti(&rect, screen_co[0], screen_co[1]) &&
513                                     BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], INT_MAX))
514                                 {
515                                         BKE_mask_point_select_set(point, select);
516                                         BKE_mask_point_select_set_handle(point, select);
517                                 }
518
519                                 change = TRUE;
520                         }
521                 }
522         }
523
524         if (change) {
525                 ED_mask_select_flush_all(mask);
526
527                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
528         }
529
530         return change;
531 }
532
533 static int clip_lasso_select_exec(bContext *C, wmOperator *op)
534 {
535         int mcords_tot;
536         int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
537
538         if (mcords) {
539                 short select;
540
541                 select = !RNA_boolean_get(op->ptr, "deselect");
542                 do_lasso_select_mask(C, mcords, mcords_tot, select);
543
544                 MEM_freeN(mcords);
545
546                 return OPERATOR_FINISHED;
547         }
548         return OPERATOR_PASS_THROUGH;
549 }
550
551 void MASK_OT_select_lasso(wmOperatorType *ot)
552 {
553         /* identifiers */
554         ot->name = "Lasso Select";
555         ot->description = "Select markers using lasso selection";
556         ot->idname = "MASK_OT_select_lasso";
557
558         /* api callbacks */
559         ot->invoke = WM_gesture_lasso_invoke;
560         ot->modal = WM_gesture_lasso_modal;
561         ot->exec = clip_lasso_select_exec;
562         ot->poll = ED_maskedit_mask_poll;
563         ot->cancel = WM_gesture_lasso_cancel;
564
565         /* flags */
566         ot->flag = OPTYPE_UNDO;
567
568         /* properties */
569         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
570         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items");
571         RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection instead of deselecting everything first");
572 }
573
574 /********************** circle select operator *********************/
575
576 static int mask_spline_point_inside_ellipse(BezTriple *bezt, float offset[2], float ellipse[2])
577 {
578         /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
579         float x, y;
580
581         x = (bezt->vec[1][0] - offset[0]) * ellipse[0];
582         y = (bezt->vec[1][1] - offset[1]) * ellipse[1];
583
584         return x * x + y * y < 1.0f;
585 }
586
587 static int circle_select_exec(bContext *C, wmOperator *op)
588 {
589         ScrArea *sa = CTX_wm_area(C);
590         ARegion *ar = CTX_wm_region(C);
591
592         Mask *mask = CTX_data_edit_mask(C);
593         MaskLayer *masklay;
594         int i;
595
596         int x, y, radius, width, height, mode, change = FALSE;
597         float zoomx, zoomy, offset[2], ellipse[2];
598
599         /* get operator properties */
600         x = RNA_int_get(op->ptr, "x");
601         y = RNA_int_get(op->ptr, "y");
602         radius = RNA_int_get(op->ptr, "radius");
603
604         mode = RNA_int_get(op->ptr, "gesture_mode");
605
606         /* compute ellipse and position in unified coordinates */
607         ED_mask_get_size(sa, &width, &height);
608         ED_mask_zoom(sa, ar, &zoomx, &zoomy);
609         width = height = MAX2(width, height);
610
611         ellipse[0] = width * zoomx / radius;
612         ellipse[1] = height * zoomy / radius;
613
614         ED_mask_point_pos(sa, ar, x, y, &offset[0], &offset[1]);
615
616         /* do actual selection */
617         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
618                 MaskSpline *spline;
619
620                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
621                         continue;
622                 }
623
624                 for (spline = masklay->splines.first; spline; spline = spline->next) {
625                         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
626
627                         for (i = 0; i < spline->tot_point; i++) {
628                                 MaskSplinePoint *point = &spline->points[i];
629                                 MaskSplinePoint *point_deform = &points_array[i];
630
631                                 if (mask_spline_point_inside_ellipse(&point_deform->bezt, offset, ellipse)) {
632                                         BKE_mask_point_select_set(point, mode == GESTURE_MODAL_SELECT);
633                                         BKE_mask_point_select_set_handle(point, mode == GESTURE_MODAL_SELECT);
634
635                                         change = TRUE;
636                                 }
637                         }
638                 }
639         }
640
641         if (change) {
642                 ED_mask_select_flush_all(mask);
643
644                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
645
646                 return OPERATOR_FINISHED;
647         }
648
649         return OPERATOR_CANCELLED;
650 }
651
652 void MASK_OT_select_circle(wmOperatorType *ot)
653 {
654         /* identifiers */
655         ot->name = "Circle Select";
656         ot->description = "Select markers using circle selection";
657         ot->idname = "MASK_OT_select_circle";
658
659         /* api callbacks */
660         ot->invoke = WM_gesture_circle_invoke;
661         ot->modal = WM_gesture_circle_modal;
662         ot->exec = circle_select_exec;
663         ot->poll = ED_maskedit_mask_poll;
664
665         /* flags */
666         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
667
668         /* properties */
669         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
670         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
671         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
672         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
673 }
674
675 static int mask_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
676 {
677         ScrArea *sa = CTX_wm_area(C);
678         ARegion *ar = CTX_wm_region(C);
679
680         Mask *mask = CTX_data_edit_mask(C);
681         MaskLayer *masklay;
682         MaskSpline *spline;
683         MaskSplinePoint *point = NULL;
684         float co[2];
685         int do_select = !RNA_boolean_get(op->ptr, "deselect");
686
687         int is_handle = 0;
688         const float threshold = 19;
689         int change = FALSE;
690
691         ED_mask_mouse_pos(sa, ar, event, co);
692
693         point = ED_mask_point_find_nearest(C, mask, co, threshold, &masklay, &spline, &is_handle, NULL);
694
695         if (point) {
696                 ED_mask_spline_select_set(spline, do_select);
697                 masklay->act_spline = spline;
698                 masklay->act_point = point;
699
700                 change = TRUE;
701         }
702
703         if (change) {
704                 ED_mask_select_flush_all(mask);
705
706                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
707
708                 return OPERATOR_FINISHED;
709         }
710
711         return OPERATOR_CANCELLED;
712 }
713
714 void MASK_OT_select_linked_pick(wmOperatorType *ot)
715 {
716         /* identifiers */
717         ot->name = "Select Linked";
718         ot->idname = "MASK_OT_select_linked_pick";
719         ot->description = "(De)select all points linked to the curve under the mouse cursor";
720
721         /* api callbacks */
722         ot->invoke = mask_select_linked_pick_invoke;
723         ot->poll = ED_maskedit_mask_poll;
724
725         /* flags */
726         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
727
728         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "");
729 }
730
731 static int mask_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
732 {
733         Mask *mask = CTX_data_edit_mask(C);
734         MaskLayer *masklay;
735
736         int change = FALSE;
737
738         /* do actual selection */
739         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
740                 MaskSpline *spline;
741
742                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
743                         continue;
744                 }
745
746                 for (spline = masklay->splines.first; spline; spline = spline->next) {
747                         if (ED_mask_spline_select_check(spline)) {
748                                 ED_mask_spline_select_set(spline, TRUE);
749                                 change = TRUE;
750                         }
751                 }
752         }
753
754         if (change) {
755                 ED_mask_select_flush_all(mask);
756
757                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
758
759                 return OPERATOR_FINISHED;
760         }
761
762         return OPERATOR_CANCELLED;
763 }
764
765 void MASK_OT_select_linked(wmOperatorType *ot)
766 {
767         /* identifiers */
768         ot->name = "Select Linked All";
769         ot->idname = "MASK_OT_select_linked";
770         ot->description = "Select all vertices linked to the active mesh";
771
772         /* api callbacks */
773         ot->exec = mask_select_linked_exec;
774         ot->poll = ED_maskedit_mask_poll;
775
776         /* flags */
777         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
778 }