Replace all old DAG calls with direct calls to new DEG and remove BKE_depsgraph.h
[blender.git] / source / blender / editors / mask / mask_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) 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_ops.c
29  *  \ingroup edmask
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "BLI_listbase.h"
35 #include "BLI_math.h"
36
37 #include "BKE_context.h"
38 #include "BKE_main.h"
39 #include "BKE_mask.h"
40
41 #include "DEG_depsgraph.h"
42
43 #include "DNA_scene_types.h"
44 #include "DNA_mask_types.h"
45 #include "DNA_object_types.h"  /* SELECT */
46
47 #include "WM_api.h"
48 #include "WM_types.h"
49
50 #include "ED_clip.h"
51 #include "ED_image.h"
52 #include "ED_keyframing.h"
53 #include "ED_mask.h"
54 #include "ED_screen.h"
55
56 #include "RNA_access.h"
57 #include "RNA_define.h"
58
59 #include "mask_intern.h"  /* own include */
60
61 /******************** utility functions *********************/
62
63 static void mask_point_scaled_handle(/*const*/ MaskSplinePoint *point, /*const*/ eMaskWhichHandle which_handle,
64                                      const float scalex, const float scaley, float handle[2])
65 {
66         BKE_mask_point_handle(point, which_handle, handle);
67         handle[0] *= scalex;
68         handle[1] *= scaley;
69 }
70
71 MaskSplinePoint *ED_mask_point_find_nearest(const bContext *C, Mask *mask, const float normal_co[2], const float threshold,
72                                             MaskLayer **masklay_r, MaskSpline **spline_r,
73                                             eMaskWhichHandle *which_handle_r, float *score)
74 {
75         ScrArea *sa = CTX_wm_area(C);
76         ARegion *ar = CTX_wm_region(C);
77
78         MaskLayer *masklay;
79         MaskLayer *point_masklay = NULL;
80         MaskSpline *point_spline = NULL;
81         MaskSplinePoint *point = NULL;
82         float co[2];
83         const float threshold_sq = threshold * threshold;
84         float len_sq = FLT_MAX, scalex, scaley;
85         eMaskWhichHandle which_handle = MASK_WHICH_HANDLE_NONE;
86         int width, height;
87
88         ED_mask_get_size(sa, &width, &height);
89         ED_mask_pixelspace_factor(sa, ar, &scalex, &scaley);
90
91         co[0] = normal_co[0] * scalex;
92         co[1] = normal_co[1] * scaley;
93
94         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
95                 MaskSpline *spline;
96
97                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
98                         continue;
99                 }
100
101                 for (spline = masklay->splines.first; spline; spline = spline->next) {
102                         MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
103
104                         int i;
105
106                         for (i = 0; i < spline->tot_point; i++) {
107                                 MaskSplinePoint *cur_point = &spline->points[i];
108                                 MaskSplinePoint *cur_point_deform = &points_array[i];
109                                 eMaskWhichHandle cur_which_handle = MASK_WHICH_HANDLE_NONE;
110                                 BezTriple *bezt = &cur_point_deform->bezt;
111                                 float cur_len_sq, vec[2];
112
113                                 vec[0] = bezt->vec[1][0] * scalex;
114                                 vec[1] = bezt->vec[1][1] * scaley;
115
116                                 cur_len_sq = len_squared_v2v2(co, vec);
117
118                                 if (cur_len_sq < len_sq) {
119                                         point_spline = spline;
120                                         point_masklay = masklay;
121                                         point = cur_point;
122                                         len_sq = cur_len_sq;
123                                         which_handle = MASK_WHICH_HANDLE_NONE;
124                                 }
125
126                                 if (BKE_mask_point_handles_mode_get(cur_point_deform) == MASK_HANDLE_MODE_STICK) {
127                                         float handle[2];
128                                         mask_point_scaled_handle(cur_point_deform, MASK_WHICH_HANDLE_STICK, scalex, scaley, handle);
129                                         cur_len_sq = len_squared_v2v2(co, handle);
130                                         cur_which_handle = MASK_WHICH_HANDLE_STICK;
131                                 }
132                                 else {
133                                         float handle_left[2], handle_right[2];
134                                         float len_left_sq, len_right_sq;
135                                         mask_point_scaled_handle(cur_point_deform, MASK_WHICH_HANDLE_LEFT, scalex, scaley, handle_left);
136                                         mask_point_scaled_handle(cur_point_deform, MASK_WHICH_HANDLE_RIGHT, scalex, scaley, handle_right);
137
138                                         len_left_sq = len_squared_v2v2(co, handle_left);
139                                         len_right_sq = len_squared_v2v2(co, handle_right);
140                                         if (i == 0) {
141                                                 if (len_left_sq <= len_right_sq) {
142                                                         if (bezt->h1 != HD_VECT) {
143                                                                 cur_which_handle = MASK_WHICH_HANDLE_LEFT;
144                                                                 cur_len_sq = len_left_sq;
145                                                         }
146                                                 }
147                                                 else if (bezt->h2 != HD_VECT) {
148                                                         cur_which_handle = MASK_WHICH_HANDLE_RIGHT;
149                                                         cur_len_sq = len_right_sq;
150                                                 }
151                                         }
152                                         else {
153                                                 if (len_right_sq <= len_left_sq) {
154                                                         if (bezt->h2 != HD_VECT) {
155                                                                 cur_which_handle = MASK_WHICH_HANDLE_RIGHT;
156                                                                 cur_len_sq = len_right_sq;
157                                                         }
158                                                 }
159                                                 else if (bezt->h1 != HD_VECT) {
160                                                         cur_which_handle = MASK_WHICH_HANDLE_LEFT;
161                                                         cur_len_sq = len_left_sq;
162                                                 }
163                                         }
164                                 }
165
166                                 if (cur_len_sq <= len_sq && cur_which_handle != MASK_WHICH_HANDLE_NONE) {
167                                         point_masklay = masklay;
168                                         point_spline = spline;
169                                         point = cur_point;
170                                         len_sq = cur_len_sq;
171                                         which_handle = cur_which_handle;
172                                 }
173                         }
174                 }
175         }
176
177         if (len_sq < threshold_sq) {
178                 if (masklay_r)
179                         *masklay_r = point_masklay;
180
181                 if (spline_r)
182                         *spline_r = point_spline;
183
184                 if (which_handle_r)
185                         *which_handle_r = which_handle;
186
187                 if (score)
188                         *score = sqrtf(len_sq);
189
190                 return point;
191         }
192
193         if (masklay_r)
194                 *masklay_r = NULL;
195
196         if (spline_r)
197                 *spline_r = NULL;
198
199         if (which_handle_r)
200                 *which_handle_r = MASK_WHICH_HANDLE_NONE;
201
202         return NULL;
203 }
204
205 bool ED_mask_feather_find_nearest(const bContext *C, Mask *mask, const float normal_co[2], const float threshold,
206                                   MaskLayer **masklay_r, MaskSpline **spline_r, MaskSplinePoint **point_r,
207                                   MaskSplinePointUW **uw_r, float *score)
208 {
209         ScrArea *sa = CTX_wm_area(C);
210         ARegion *ar = CTX_wm_region(C);
211
212         MaskLayer *masklay, *point_masklay = NULL;
213         MaskSpline *point_spline = NULL;
214         MaskSplinePoint *point = NULL;
215         MaskSplinePointUW *uw = NULL;
216         const float threshold_sq = threshold * threshold;
217         float len = FLT_MAX, co[2];
218         float scalex, scaley;
219         int width, height;
220
221         ED_mask_get_size(sa, &width, &height);
222         ED_mask_pixelspace_factor(sa, ar, &scalex, &scaley);
223
224         co[0] = normal_co[0] * scalex;
225         co[1] = normal_co[1] * scaley;
226
227         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
228                 MaskSpline *spline;
229
230                 for (spline = masklay->splines.first; spline; spline = spline->next) {
231                         //MaskSplinePoint *points_array = BKE_mask_spline_point_array(spline);
232
233                         int i, tot_feather_point;
234                         float (*feather_points)[2], (*fp)[2];
235
236                         if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
237                                 continue;
238                         }
239
240                         feather_points = fp = BKE_mask_spline_feather_points(spline, &tot_feather_point);
241
242                         for (i = 0; i < spline->tot_point; i++) {
243                                 int j;
244                                 MaskSplinePoint *cur_point = &spline->points[i];
245
246                                 for (j = 0; j <= cur_point->tot_uw; j++) {
247                                         float cur_len_sq, vec[2];
248
249                                         vec[0] = (*fp)[0] * scalex;
250                                         vec[1] = (*fp)[1] * scaley;
251
252                                         cur_len_sq = len_squared_v2v2(vec, co);
253
254                                         if (point == NULL || cur_len_sq < len) {
255                                                 if (j == 0)
256                                                         uw = NULL;
257                                                 else
258                                                         uw = &cur_point->uw[j - 1];
259
260                                                 point_masklay = masklay;
261                                                 point_spline = spline;
262                                                 point = cur_point;
263                                                 len = cur_len_sq;
264                                         }
265
266                                         fp++;
267                                 }
268                         }
269
270                         MEM_freeN(feather_points);
271                 }
272         }
273
274         if (len < threshold_sq) {
275                 if (masklay_r)
276                         *masklay_r = point_masklay;
277
278                 if (spline_r)
279                         *spline_r = point_spline;
280
281                 if (point_r)
282                         *point_r = point;
283
284                 if (uw_r)
285                         *uw_r = uw;
286
287                 if (score)
288                         *score = sqrtf(len);
289
290                 return true;
291         }
292
293         if (masklay_r)
294                 *masklay_r = NULL;
295
296         if (spline_r)
297                 *spline_r = NULL;
298
299         if (point_r)
300                 *point_r = NULL;
301
302         return false;
303 }
304
305
306 /******************** create new mask *********************/
307
308 Mask *ED_mask_new(bContext *C, const char *name)
309 {
310         ScrArea *sa = CTX_wm_area(C);
311         Main *bmain = CTX_data_main(C);
312         Mask *mask;
313
314         mask = BKE_mask_new(bmain, name);
315
316         if (sa && sa->spacedata.first) {
317                 switch (sa->spacetype) {
318                         case SPACE_CLIP:
319                         {
320                                 SpaceClip *sc = sa->spacedata.first;
321                                 ED_space_clip_set_mask(C, sc, mask);
322                                 break;
323                         }
324                         case SPACE_SEQ:
325                         {
326                                 /* do nothing */
327                                 break;
328                         }
329                         case SPACE_IMAGE:
330                         {
331                                 SpaceImage *sima = sa->spacedata.first;
332                                 ED_space_image_set_mask(C, sima, mask);
333                                 break;
334                         }
335                 }
336         }
337
338         return mask;
339 }
340
341 /* Get ative layer. Will create mask/layer to be sure there's an active layer.  */
342 MaskLayer *ED_mask_layer_ensure(bContext *C)
343 {
344         Mask *mask = CTX_data_edit_mask(C);
345         MaskLayer *mask_layer;
346
347         if (mask == NULL) {
348                 /* If there's no active mask, create one. */
349                 mask = ED_mask_new(C, NULL);
350         }
351
352         mask_layer = BKE_mask_layer_active(mask);
353         if (mask_layer == NULL) {
354                 /* If there's no active mask layer, create one. */
355                 mask_layer = BKE_mask_layer_new(mask, "");
356         }
357
358         return mask_layer;
359 }
360
361 static int mask_new_exec(bContext *C, wmOperator *op)
362 {
363         char name[MAX_ID_NAME - 2];
364
365         RNA_string_get(op->ptr, "name", name);
366
367         ED_mask_new(C, name);
368
369         return OPERATOR_FINISHED;
370 }
371
372 void MASK_OT_new(wmOperatorType *ot)
373 {
374         /* identifiers */
375         ot->name = "New Mask";
376         ot->description = "Create new mask";
377         ot->idname = "MASK_OT_new";
378
379         /* flags */
380         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
381
382         /* api callbacks */
383         ot->exec = mask_new_exec;
384         ot->poll = ED_operator_mask;
385
386         /* properties */
387         RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Name of new mask");
388 }
389
390 /******************** create new masklay *********************/
391
392 static int masklay_new_exec(bContext *C, wmOperator *op)
393 {
394         Mask *mask = CTX_data_edit_mask(C);
395         char name[MAX_ID_NAME - 2];
396
397         RNA_string_get(op->ptr, "name", name);
398
399         BKE_mask_layer_new(mask, name);
400         mask->masklay_act = mask->masklay_tot - 1;
401
402         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
403
404         return OPERATOR_FINISHED;
405 }
406
407 void MASK_OT_layer_new(wmOperatorType *ot)
408 {
409         /* identifiers */
410         ot->name = "Add Mask Layer";
411         ot->description = "Add new mask layer for masking";
412         ot->idname = "MASK_OT_layer_new";
413
414         /* api callbacks */
415         ot->exec = masklay_new_exec;
416         ot->poll = ED_maskedit_poll;
417
418         /* flags */
419         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
420
421         /* properties */
422         RNA_def_string(ot->srna, "name", NULL, MAX_ID_NAME - 2, "Name", "Name of new mask layer");
423 }
424
425 /******************** remove mask layer *********************/
426
427 static int masklay_remove_exec(bContext *C, wmOperator *UNUSED(op))
428 {
429         Mask *mask = CTX_data_edit_mask(C);
430         MaskLayer *masklay = BKE_mask_layer_active(mask);
431
432         if (masklay) {
433                 BKE_mask_layer_remove(mask, masklay);
434
435                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
436         }
437
438         return OPERATOR_FINISHED;
439 }
440
441 void MASK_OT_layer_remove(wmOperatorType *ot)
442 {
443         /* identifiers */
444         ot->name = "Remove Mask Layer";
445         ot->description = "Remove mask layer";
446         ot->idname = "MASK_OT_layer_remove";
447
448         /* api callbacks */
449         ot->exec = masklay_remove_exec;
450         ot->poll = ED_maskedit_poll;
451
452         /* flags */
453         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
454 }
455
456 /******************** slide *********************/
457
458 enum {
459         SLIDE_ACTION_NONE    = 0,
460         SLIDE_ACTION_POINT   = 1,
461         SLIDE_ACTION_HANDLE  = 2,
462         SLIDE_ACTION_FEATHER = 3,
463         SLIDE_ACTION_SPLINE  = 4
464 };
465
466 typedef struct SlidePointData {
467         /* Generic fields. */
468         short event_invoke_type;
469         int action;
470         Mask *mask;
471         MaskLayer *masklay;
472         MaskSpline *spline, *orig_spline;
473         MaskSplinePoint *point;
474         MaskSplinePointUW *uw;
475         eMaskWhichHandle which_handle;
476         int width, height;
477
478         float prev_mouse_coord[2];
479         float no[2];
480
481         bool is_curvature_only,
482              is_accurate,
483              is_initial_feather,
484              is_overall_feather;
485
486         bool is_sliding_new_point;
487
488         /* Data needed to restre the state. */
489         float vec[3][3];
490         char old_h1, old_h2;
491
492         /* Point sliding. */
493
494         /* Handle sliding. */
495         float orig_handle_coord[2], prev_handle_coord[2];
496
497         /* Feather sliding. */
498         float prev_feather_coord[2];
499         float weight, weight_scalar;
500 } SlidePointData;
501
502 static void mask_point_undistort_pos(SpaceClip *sc, float r_co[2], const float co[2])
503 {
504         BKE_mask_coord_to_movieclip(sc->clip, &sc->user, r_co, co);
505         ED_clip_point_undistorted_pos(sc, r_co, r_co);
506         BKE_mask_coord_from_movieclip(sc->clip, &sc->user, r_co, r_co);
507 }
508
509 static bool spline_under_mouse_get(const bContext *C,
510                                    Mask *mask, const float co[2],
511                                    MaskLayer **mask_layer_r,
512                                    MaskSpline **mask_spline_r)
513 {
514         const float threshold = 19.0f;
515         ScrArea *sa = CTX_wm_area(C);
516         SpaceClip *sc = CTX_wm_space_clip(C);
517         MaskLayer *mask_layer;
518         int width, height;
519         float pixel_co[2];
520         float closest_dist_squared = 0.0f;
521         MaskLayer *closest_layer = NULL;
522         MaskSpline *closest_spline = NULL;
523         bool undistort = false;
524         *mask_layer_r = NULL;
525         *mask_spline_r = NULL;
526         ED_mask_get_size(sa, &width, &height);
527         pixel_co[0] = co[0] * width;
528         pixel_co[1] = co[1] * height;
529         if (sc != NULL) {
530                 undistort = (sc->clip != NULL) &&
531                             (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) != 0;
532         }
533         for (mask_layer = mask->masklayers.first;
534              mask_layer != NULL;
535              mask_layer = mask_layer->next)
536         {
537                 MaskSpline *spline;
538                 if (mask_layer->restrictflag & MASK_RESTRICT_SELECT) {
539                         continue;
540                 }
541
542                 for (spline = mask_layer->splines.first;
543                      spline != NULL;
544                      spline = spline->next)
545                 {
546                         MaskSplinePoint *points_array;
547                         float min[2], max[2], center[2];
548                         float dist_squared;
549                         int i;
550                         float max_bb_side;
551                         if ((spline->flag & SELECT) == 0) {
552                                 continue;
553                         }
554
555                         points_array = BKE_mask_spline_point_array(spline);
556                         INIT_MINMAX2(min, max);
557                         for (i = 0; i < spline->tot_point; i++) {
558                                 MaskSplinePoint *point_deform = &points_array[i];
559                                 BezTriple *bezt = &point_deform->bezt;
560
561                                 float vert[2];
562
563                                 copy_v2_v2(vert, bezt->vec[1]);
564
565                                 if (undistort) {
566                                         mask_point_undistort_pos(sc, vert, vert);
567                                 }
568
569                                 minmax_v2v2_v2(min, max, vert);
570                         }
571
572                         center[0] = (min[0] + max[0]) / 2.0f * width;
573                         center[1] = (min[1] + max[1]) / 2.0f * height;
574                         dist_squared = len_squared_v2v2(pixel_co, center);
575                         max_bb_side = min_ff((max[0] - min[0]) * width, (max[1] - min[1]) * height);
576                         if (dist_squared <= max_bb_side * max_bb_side * 0.5f &&
577                             (closest_spline == NULL || dist_squared < closest_dist_squared))
578                         {
579                                 closest_layer = mask_layer;
580                                 closest_spline = spline;
581                                 closest_dist_squared = dist_squared;
582                         }
583                 }
584         }
585         if (closest_dist_squared < SQUARE(threshold) && closest_spline != NULL) {
586                 float diff_score;
587                 if (ED_mask_find_nearest_diff_point(C, mask, co, threshold,
588                                                     false, NULL, true, false,
589                                                     NULL, NULL, NULL, NULL,
590                                                     &diff_score))
591                 {
592                         if (SQUARE(diff_score) < closest_dist_squared) {
593                                 return false;
594                         }
595                 }
596
597                 *mask_layer_r = closest_layer;
598                 *mask_spline_r = closest_spline;
599                 return true;
600         }
601         return false;
602 }
603
604 static bool slide_point_check_initial_feather(MaskSpline *spline)
605 {
606         int i;
607
608         for (i = 0; i < spline->tot_point; i++) {
609                 MaskSplinePoint *point = &spline->points[i];
610
611                 if (point->bezt.weight != 0.0f) {
612                         return false;
613                 }
614         }
615
616         return true;
617 }
618
619 static void select_sliding_point(Mask *mask, MaskLayer *mask_layer, MaskSpline *spline,
620                                  MaskSplinePoint *point, eMaskWhichHandle which_handle)
621 {
622         ED_mask_select_toggle_all(mask, SEL_DESELECT);
623
624         switch (which_handle) {
625                 case MASK_WHICH_HANDLE_NONE:
626                         BKE_mask_point_select_set(point, true);
627                         break;
628                 case MASK_WHICH_HANDLE_LEFT:
629                         point->bezt.f1 |= SELECT;
630                         break;
631                 case MASK_WHICH_HANDLE_RIGHT:
632                         point->bezt.f3 |= SELECT;
633                         break;
634                 case MASK_WHICH_HANDLE_STICK:
635                         point->bezt.f1 |= SELECT;
636                         point->bezt.f3 |= SELECT;
637                         break;
638                 default:
639                         BLI_assert(!"Unexpected situation in select_sliding_point()");
640         }
641
642         mask_layer->act_spline = spline;
643         mask_layer->act_point = point;
644         ED_mask_select_flush_all(mask);
645 }
646
647 static void check_sliding_handle_type(MaskSplinePoint *point, eMaskWhichHandle which_handle)
648 {
649         BezTriple *bezt = &point->bezt;
650
651         if (which_handle == MASK_WHICH_HANDLE_LEFT) {
652                 if (bezt->h1 == HD_VECT) {
653                         bezt->h1 = HD_FREE;
654                 }
655                 else if (bezt->h1 == HD_AUTO) {
656                         bezt->h1 = HD_ALIGN_DOUBLESIDE;
657                         bezt->h2 = HD_ALIGN_DOUBLESIDE;
658                 }
659         }
660         else if (which_handle == MASK_WHICH_HANDLE_RIGHT) {
661                 if (bezt->h2 == HD_VECT) {
662                         bezt->h2 = HD_FREE;
663                 }
664                 else if (bezt->h2 == HD_AUTO) {
665                         bezt->h1 = HD_ALIGN_DOUBLESIDE;
666                         bezt->h2 = HD_ALIGN_DOUBLESIDE;
667                 }
668         }
669 }
670
671 static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent *event)
672 {
673         ScrArea *sa = CTX_wm_area(C);
674         ARegion *ar = CTX_wm_region(C);
675
676         Mask *mask = CTX_data_edit_mask(C);
677         SlidePointData *customdata = NULL;
678         MaskLayer *masklay, *cv_masklay, *feather_masklay;
679         MaskSpline *spline, *cv_spline, *feather_spline;
680         MaskSplinePoint *point, *cv_point, *feather_point;
681         MaskSplinePointUW *uw = NULL;
682         int width, height, action = SLIDE_ACTION_NONE;
683         const bool slide_feather = RNA_boolean_get(op->ptr, "slide_feather");
684         float co[2], cv_score, feather_score;
685         const float threshold = 19;
686         eMaskWhichHandle which_handle;
687
688         ED_mask_mouse_pos(sa, ar, event->mval, co);
689         ED_mask_get_size(sa, &width, &height);
690
691         cv_point = ED_mask_point_find_nearest(C, mask, co, threshold, &cv_masklay, &cv_spline, &which_handle, &cv_score);
692
693         if (ED_mask_feather_find_nearest(C, mask, co, threshold, &feather_masklay, &feather_spline, &feather_point, &uw, &feather_score)) {
694                 if (slide_feather || !cv_point || feather_score < cv_score) {
695                         action = SLIDE_ACTION_FEATHER;
696
697                         masklay = feather_masklay;
698                         spline = feather_spline;
699                         point = feather_point;
700                 }
701         }
702
703         if (cv_point && action == SLIDE_ACTION_NONE) {
704                 if (which_handle != MASK_WHICH_HANDLE_NONE)
705                         action = SLIDE_ACTION_HANDLE;
706                 else
707                         action = SLIDE_ACTION_POINT;
708
709                 masklay = cv_masklay;
710                 spline = cv_spline;
711                 point = cv_point;
712         }
713
714         if (action == SLIDE_ACTION_NONE) {
715                 if (spline_under_mouse_get(C, mask, co, &masklay, &spline)) {
716                         action = SLIDE_ACTION_SPLINE;
717                         point = NULL;
718                 }
719         }
720
721         if (action != SLIDE_ACTION_NONE) {
722                 customdata = MEM_callocN(sizeof(SlidePointData), "mask slide point data");
723                 customdata->event_invoke_type = event->type;
724                 customdata->mask = mask;
725                 customdata->masklay = masklay;
726                 customdata->spline = spline;
727                 customdata->point = point;
728                 customdata->width = width;
729                 customdata->height = height;
730                 customdata->action = action;
731                 customdata->uw = uw;
732
733                 customdata->is_sliding_new_point = RNA_boolean_get(op->ptr, "is_new_point");
734
735                 if (customdata->action != SLIDE_ACTION_SPLINE) {
736                         customdata->old_h1 = point->bezt.h1;
737                         customdata->old_h2 = point->bezt.h2;
738                         select_sliding_point(mask, masklay, spline, point, which_handle);
739                         check_sliding_handle_type(point, which_handle);
740                 }
741
742                 if (uw) {
743                         float co_uw[2];
744                         float weight_scalar = BKE_mask_point_weight_scalar(spline, point, uw->u);
745
746                         customdata->weight = uw->w;
747                         customdata->weight_scalar = weight_scalar;
748                         BKE_mask_point_segment_co(spline, point, uw->u, co_uw);
749                         BKE_mask_point_normal(spline, point, uw->u, customdata->no);
750
751                         madd_v2_v2v2fl(customdata->prev_feather_coord, co_uw, customdata->no, uw->w * weight_scalar);
752                 }
753                 else if (customdata->action != SLIDE_ACTION_SPLINE) {
754                         BezTriple *bezt = &point->bezt;
755
756                         customdata->weight = bezt->weight;
757                         customdata->weight_scalar = 1.0f;
758                         BKE_mask_point_normal(spline, point, 0.0f, customdata->no);
759
760                         madd_v2_v2v2fl(customdata->prev_feather_coord, bezt->vec[1], customdata->no, bezt->weight);
761                 }
762
763                 if (customdata->action == SLIDE_ACTION_FEATHER) {
764                         customdata->is_initial_feather = slide_point_check_initial_feather(spline);
765                 }
766
767                 if (customdata->action != SLIDE_ACTION_SPLINE) {
768                         copy_m3_m3(customdata->vec, point->bezt.vec);
769                         if (which_handle != MASK_WHICH_HANDLE_NONE) {
770                                 BKE_mask_point_handle(point, which_handle, customdata->orig_handle_coord);
771                                 copy_v2_v2(customdata->prev_handle_coord, customdata->orig_handle_coord);
772                         }
773                 }
774                 customdata->which_handle = which_handle;
775
776                 ED_mask_mouse_pos(sa, ar, event->mval, customdata->prev_mouse_coord);
777         }
778
779         return customdata;
780 }
781
782 static int slide_point_invoke(bContext *C, wmOperator *op, const wmEvent *event)
783 {
784         Mask *mask = CTX_data_edit_mask(C);
785         SlidePointData *slidedata;
786
787         if (mask == NULL) {
788                 return OPERATOR_PASS_THROUGH;
789         }
790
791         slidedata = slide_point_customdata(C, op, event);
792
793         if (slidedata) {
794                 op->customdata = slidedata;
795
796                 WM_event_add_modal_handler(C, op);
797
798                 slidedata->masklay->act_spline = slidedata->spline;
799                 slidedata->masklay->act_point = slidedata->point;
800
801                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
802
803                 return OPERATOR_RUNNING_MODAL;
804         }
805
806         return OPERATOR_PASS_THROUGH;
807 }
808
809 static void slide_point_delta_all_feather(SlidePointData *data, float delta)
810 {
811         int i;
812
813         for (i = 0; i < data->spline->tot_point; i++) {
814                 MaskSplinePoint *point = &data->spline->points[i];
815                 MaskSplinePoint *orig_point = &data->orig_spline->points[i];
816
817                 point->bezt.weight = orig_point->bezt.weight + delta;
818                 if (point->bezt.weight < 0.0f) {
819                         point->bezt.weight = 0.0f;
820                 }
821         }
822 }
823
824 static void slide_point_restore_spline(SlidePointData *data)
825 {
826         int i;
827
828         for (i = 0; i < data->spline->tot_point; i++) {
829                 MaskSplinePoint *point = &data->spline->points[i];
830                 MaskSplinePoint *orig_point = &data->orig_spline->points[i];
831                 int j;
832
833                 point->bezt = orig_point->bezt;
834
835                 for (j = 0; j < point->tot_uw; j++)
836                         point->uw[j] = orig_point->uw[j];
837         }
838 }
839
840 static void cancel_slide_point(SlidePointData *data)
841 {
842         /* cancel sliding */
843
844         if (data->orig_spline) {
845                 slide_point_restore_spline(data);
846         }
847         else {
848                 if (data->action == SLIDE_ACTION_FEATHER) {
849                         if (data->uw)
850                                 data->uw->w = data->weight;
851                         else
852                                 data->point->bezt.weight = data->weight;
853                 }
854                 else if (data->action != SLIDE_ACTION_SPLINE) {
855                         copy_m3_m3(data->point->bezt.vec, data->vec);
856                         data->point->bezt.h1 = data->old_h1;
857                         data->point->bezt.h2 = data->old_h2;
858                 }
859         }
860 }
861
862 static void free_slide_point_data(SlidePointData *data)
863 {
864         if (data->orig_spline)
865                 BKE_mask_spline_free(data->orig_spline);
866
867         MEM_freeN(data);
868 }
869
870 static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event)
871 {
872         SlidePointData *data = (SlidePointData *)op->customdata;
873         BezTriple *bezt = &data->point->bezt;
874         float co[2];
875
876         switch (event->type) {
877                 case LEFTALTKEY:
878                 case RIGHTALTKEY:
879                 case LEFTSHIFTKEY:
880                 case RIGHTSHIFTKEY:
881                         if (ELEM(event->type, LEFTALTKEY, RIGHTALTKEY)) {
882                                 if (data->action == SLIDE_ACTION_FEATHER) {
883                                         data->is_overall_feather = (event->val == KM_PRESS);
884                                 }
885                                 else {
886                                         data->is_curvature_only = (event->val == KM_PRESS);
887                                 }
888                         }
889
890                         if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY))
891                                 data->is_accurate = (event->val == KM_PRESS);
892
893                         ATTR_FALLTHROUGH;  /* update CV position */
894                 case MOUSEMOVE:
895                 {
896                         ScrArea *sa = CTX_wm_area(C);
897                         ARegion *ar = CTX_wm_region(C);
898                         float delta[2];
899
900                         ED_mask_mouse_pos(sa, ar, event->mval, co);
901                         sub_v2_v2v2(delta, co, data->prev_mouse_coord);
902                         if (data->is_accurate) {
903                                 mul_v2_fl(delta, 0.2f);
904                         }
905                         copy_v2_v2(data->prev_mouse_coord, co);
906
907                         if (data->action == SLIDE_ACTION_HANDLE) {
908                                 float new_handle[2];
909
910                                 if (data->is_sliding_new_point && data->which_handle == MASK_WHICH_HANDLE_STICK) {
911                                         if (ELEM(data->point, &data->spline->points[0],
912                                                               &data->spline->points[data->spline->tot_point - 1]))
913                                         {
914                                                 SWAP(float, delta[0], delta[1]);
915                                                 delta[1] *= -1;
916
917                                                 /* flip last point */
918                                                 if (data->point != &data->spline->points[0]) {
919                                                         negate_v2(delta);
920                                                 }
921                                         }
922                                 }
923
924                                 add_v2_v2v2(new_handle, data->prev_handle_coord, delta);
925
926                                 BKE_mask_point_set_handle(data->point, data->which_handle,
927                                                           new_handle, data->is_curvature_only,
928                                                           data->orig_handle_coord, data->vec);
929                                 BKE_mask_point_handle(data->point, data->which_handle, data->prev_handle_coord);
930
931                                 if (data->is_sliding_new_point) {
932                                         if (ELEM(data->which_handle, MASK_WHICH_HANDLE_LEFT, MASK_WHICH_HANDLE_RIGHT)) {
933                                                 float vec[2];
934                                                 short self_handle = (data->which_handle == MASK_WHICH_HANDLE_LEFT) ? 0 : 2;
935                                                 short other_handle = (data->which_handle == MASK_WHICH_HANDLE_LEFT) ? 2 : 0;
936
937                                                 sub_v2_v2v2(vec, bezt->vec[1], bezt->vec[self_handle]);
938                                                 add_v2_v2v2(bezt->vec[other_handle], bezt->vec[1], vec);
939                                         }
940                                 }
941                         }
942                         else if (data->action == SLIDE_ACTION_POINT) {
943                                 add_v2_v2(bezt->vec[0], delta);
944                                 add_v2_v2(bezt->vec[1], delta);
945                                 add_v2_v2(bezt->vec[2], delta);
946                         }
947                         else if (data->action == SLIDE_ACTION_FEATHER) {
948                                 float vec[2], no[2], p[2], c[2], w, offco[2];
949                                 float *weight = NULL;
950                                 float weight_scalar = 1.0f;
951                                 bool is_overall_feather = data->is_overall_feather || data->is_initial_feather;
952
953                                 add_v2_v2v2(offco, data->prev_feather_coord, delta);
954
955                                 if (data->uw) {
956                                         /* project on both sides and find the closest one,
957                                          * prevents flickering when projecting onto both sides can happen */
958                                         const float u_pos = BKE_mask_spline_project_co(data->spline, data->point,
959                                                                                        data->uw->u, offco, MASK_PROJ_NEG);
960                                         const float u_neg = BKE_mask_spline_project_co(data->spline, data->point,
961                                                                                        data->uw->u, offco, MASK_PROJ_POS);
962                                         float dist_pos = FLT_MAX;
963                                         float dist_neg = FLT_MAX;
964                                         float co_pos[2];
965                                         float co_neg[2];
966                                         float u;
967
968                                         if (u_pos > 0.0f && u_pos < 1.0f) {
969                                                 BKE_mask_point_segment_co(data->spline, data->point, u_pos, co_pos);
970                                                 dist_pos = len_squared_v2v2(offco, co_pos);
971                                         }
972
973                                         if (u_neg > 0.0f && u_neg < 1.0f) {
974                                                 BKE_mask_point_segment_co(data->spline, data->point, u_neg, co_neg);
975                                                 dist_neg = len_squared_v2v2(offco, co_neg);
976                                         }
977
978                                         u = dist_pos < dist_neg ? u_pos : u_neg;
979
980                                         if (u > 0.0f && u < 1.0f) {
981                                                 data->uw->u = u;
982
983                                                 data->uw = BKE_mask_point_sort_uw(data->point, data->uw);
984                                                 weight = &data->uw->w;
985                                                 weight_scalar = BKE_mask_point_weight_scalar(data->spline, data->point, u);
986                                                 if (weight_scalar != 0.0f) {
987                                                         weight_scalar = 1.0f / weight_scalar;
988                                                 }
989
990                                                 BKE_mask_point_normal(data->spline, data->point, data->uw->u, no);
991                                                 BKE_mask_point_segment_co(data->spline, data->point, data->uw->u, p);
992                                         }
993                                 }
994                                 else {
995                                         weight = &bezt->weight;
996                                         /* weight_scalar = 1.0f; keep as is */
997                                         copy_v2_v2(no, data->no);
998                                         copy_v2_v2(p, bezt->vec[1]);
999                                 }
1000
1001                                 if (weight) {
1002                                         sub_v2_v2v2(c, offco, p);
1003                                         project_v2_v2v2(vec, c, no);
1004
1005                                         w = len_v2(vec);
1006
1007                                         if (is_overall_feather) {
1008                                                 float w_delta;
1009
1010                                                 if (dot_v2v2(no, vec) <= 0.0f)
1011                                                         w = -w;
1012
1013                                                 w_delta = w - data->weight * data->weight_scalar;
1014
1015                                                 if (data->orig_spline == NULL) {
1016                                                         /* restore weight for currently sliding point, so orig_spline would be created
1017                                                          * with original weights used
1018                                                          */
1019                                                         *weight = data->weight;
1020
1021                                                         data->orig_spline = BKE_mask_spline_copy(data->spline);
1022                                                 }
1023
1024                                                 if (data->is_initial_feather) {
1025                                                         *weight = w * weight_scalar;
1026                                                 }
1027
1028                                                 slide_point_delta_all_feather(data, w_delta);
1029                                         }
1030                                         else {
1031                                                 if (dot_v2v2(no, vec) <= 0.0f)
1032                                                         w = 0.0f;
1033
1034                                                 if (data->orig_spline) {
1035                                                         /* restore possible overall feather changes */
1036                                                         slide_point_restore_spline(data);
1037
1038                                                         BKE_mask_spline_free(data->orig_spline);
1039                                                         data->orig_spline = NULL;
1040                                                 }
1041
1042                                                 if (weight_scalar != 0.0f) {
1043                                                         *weight = w * weight_scalar;
1044                                                 }
1045                                         }
1046
1047                                         copy_v2_v2(data->prev_feather_coord, offco);
1048                                 }
1049                         }
1050                         else if (data->action == SLIDE_ACTION_SPLINE) {
1051                                 int i;
1052
1053                                 if (data->orig_spline == NULL) {
1054                                         data->orig_spline = BKE_mask_spline_copy(data->spline);
1055                                 }
1056
1057                                 for (i = 0; i < data->spline->tot_point; i++) {
1058                                         MaskSplinePoint *point = &data->spline->points[i];
1059                                         add_v2_v2(point->bezt.vec[0], delta);
1060                                         add_v2_v2(point->bezt.vec[1], delta);
1061                                         add_v2_v2(point->bezt.vec[2], delta);
1062                                 }
1063                         }
1064
1065                         WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask);
1066                         DEG_id_tag_update(&data->mask->id, 0);
1067
1068                         break;
1069                 }
1070
1071                 case LEFTMOUSE:
1072                 case RIGHTMOUSE:
1073                         if (event->type == data->event_invoke_type && event->val == KM_RELEASE) {
1074                                 Scene *scene = CTX_data_scene(C);
1075
1076                                 /* dont key sliding feather uw's */
1077                                 if ((data->action == SLIDE_ACTION_FEATHER && data->uw) == false) {
1078                                         if (IS_AUTOKEY_ON(scene)) {
1079                                                 ED_mask_layer_shape_auto_key(data->masklay, CFRA);
1080                                         }
1081                                 }
1082
1083                                 if (data->is_sliding_new_point) {
1084                                         if (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) < FLT_EPSILON) {
1085                                                 bezt->h1 = HD_VECT;
1086                                         }
1087                                         if (len_squared_v2v2(bezt->vec[2], bezt->vec[1]) < FLT_EPSILON) {
1088                                                 bezt->h2 = HD_VECT;
1089                                         }
1090                                 }
1091
1092                                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask);
1093                                 DEG_id_tag_update(&data->mask->id, 0);
1094
1095                                 free_slide_point_data(op->customdata); /* keep this last! */
1096                                 return OPERATOR_FINISHED;
1097                         }
1098                         else if (event->type != data->event_invoke_type && event->val == KM_PRESS) {
1099                                 /* pass to ESCKEY */
1100                         }
1101                         else {
1102                                 break;
1103                         }
1104
1105                 case ESCKEY:
1106                         cancel_slide_point(op->customdata);
1107
1108                         WM_event_add_notifier(C, NC_MASK | NA_EDITED, data->mask);
1109                         DEG_id_tag_update(&data->mask->id, 0);
1110
1111                         free_slide_point_data(op->customdata); /* keep this last! */
1112                         return OPERATOR_CANCELLED;
1113         }
1114
1115         return OPERATOR_RUNNING_MODAL;
1116 }
1117
1118 void MASK_OT_slide_point(wmOperatorType *ot)
1119 {
1120         PropertyRNA *prop;
1121
1122         /* identifiers */
1123         ot->name = "Slide Point";
1124         ot->description = "Slide control points";
1125         ot->idname = "MASK_OT_slide_point";
1126
1127         /* api callbacks */
1128         ot->invoke = slide_point_invoke;
1129         ot->modal = slide_point_modal;
1130         ot->poll = ED_operator_mask;
1131
1132         /* flags */
1133         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1134
1135         RNA_def_boolean(ot->srna, "slide_feather", 0, "Slide Feather", "First try to slide feather instead of vertex");
1136
1137         prop = RNA_def_boolean(ot->srna, "is_new_point", 0, "Slide New Point", "Newly created vertex is being slid");
1138         RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1139 }
1140
1141 /******************** slide spline curvature *********************/
1142
1143 typedef struct SlideSplineCurvatureData {
1144         short event_invoke_type;
1145
1146         Mask *mask;
1147         MaskLayer *mask_layer;
1148         MaskSpline *spline;
1149         MaskSplinePoint *point;
1150         float u;
1151         bool accurate;
1152
1153         BezTriple *adjust_bezt, *other_bezt;
1154         BezTriple bezt_backup, other_bezt_backup;
1155
1156         float prev_mouse_coord[2];
1157         float prev_spline_coord[2];
1158
1159         float P0[2], P1[2], P2[2], P3[3];
1160 } SlideSplineCurvatureData;
1161
1162 static void cancel_slide_spline_curvature(SlideSplineCurvatureData *slide_data)
1163 {
1164         *slide_data->adjust_bezt = slide_data->bezt_backup;
1165         *slide_data->other_bezt = slide_data->other_bezt_backup;
1166 }
1167
1168
1169 static void free_slide_spline_curvature_data(SlideSplineCurvatureData *slide_data)
1170 {
1171         MEM_freeN(slide_data);
1172 }
1173
1174 static bool slide_spline_curvature_check(bContext *C, const wmEvent *event)
1175 {
1176         Mask *mask = CTX_data_edit_mask(C);
1177         float co[2];
1178         const float threshold = 19.0f;
1179
1180         ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, co);
1181
1182         if (ED_mask_point_find_nearest(C, mask, co, threshold, NULL, NULL, NULL, NULL)) {
1183                 return false;
1184         }
1185
1186         if (ED_mask_feather_find_nearest(C, mask, co, threshold, NULL, NULL, NULL, NULL, NULL)) {
1187                 return false;
1188         }
1189
1190         return true;
1191 }
1192
1193 static SlideSplineCurvatureData *slide_spline_curvature_customdata(
1194         bContext *C, const wmEvent *event)
1195 {
1196         const float threshold = 19.0f;
1197
1198         Mask *mask = CTX_data_edit_mask(C);
1199         SlideSplineCurvatureData *slide_data;
1200         MaskLayer *mask_layer;
1201         MaskSpline *spline;
1202         MaskSplinePoint *point;
1203         float u, co[2];
1204         BezTriple *next_bezt;
1205
1206         ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, co);
1207
1208         if (!ED_mask_find_nearest_diff_point(C, mask, co, threshold, false,
1209                                              NULL, true, false,
1210                                              &mask_layer, &spline, &point, &u,
1211                                              NULL))
1212         {
1213                 return NULL;
1214         }
1215
1216         next_bezt = BKE_mask_spline_point_next_bezt(spline, spline->points, point);
1217         if (next_bezt == NULL) {
1218                 return NULL;
1219         }
1220
1221         slide_data = MEM_callocN(sizeof(SlideSplineCurvatureData), "slide curvature slide");
1222         slide_data->event_invoke_type = event->type;
1223         slide_data->mask = mask;
1224         slide_data->mask_layer = mask_layer;
1225         slide_data->spline = spline;
1226         slide_data->point = point;
1227         slide_data->u = u;
1228
1229         copy_v2_v2(slide_data->prev_mouse_coord, co);
1230         BKE_mask_point_segment_co(spline, point, u, slide_data->prev_spline_coord);
1231
1232         copy_v2_v2(slide_data->P0, point->bezt.vec[1]);
1233         copy_v2_v2(slide_data->P1, point->bezt.vec[2]);
1234         copy_v2_v2(slide_data->P2, next_bezt->vec[0]);
1235         copy_v2_v2(slide_data->P3, next_bezt->vec[1]);
1236
1237         /* Depending to which end we're closer to adjust either left or right side of the spline. */
1238         if (u <= 0.5f) {
1239                 slide_data->adjust_bezt = &point->bezt;
1240                 slide_data->other_bezt = next_bezt;
1241         }
1242         else {
1243                 slide_data->adjust_bezt = next_bezt;
1244                 slide_data->other_bezt = &point->bezt;
1245         }
1246
1247         /* Data needed for restoring state. */
1248         slide_data->bezt_backup = *slide_data->adjust_bezt;
1249         slide_data->other_bezt_backup = *slide_data->other_bezt;
1250
1251         /* Let's dont touch other side of the point for now, so set handle to FREE. */
1252         if (u < 0.5f) {
1253                 if (slide_data->adjust_bezt->h2 <= HD_VECT) {
1254                         slide_data->adjust_bezt->h2 = HD_FREE;
1255                 }
1256         }
1257         else {
1258                 if (slide_data->adjust_bezt->h1 <= HD_VECT) {
1259                         slide_data->adjust_bezt->h1 = HD_FREE;
1260                 }
1261         }
1262
1263         /* Change selection */
1264         ED_mask_select_toggle_all(mask, SEL_DESELECT);
1265         slide_data->adjust_bezt->f2 |= SELECT;
1266         slide_data->other_bezt->f2 |= SELECT;
1267         if (u < 0.5f) {
1268                 slide_data->adjust_bezt->f3 |= SELECT;
1269                 slide_data->other_bezt->f1 |= SELECT;
1270         }
1271         else {
1272                 slide_data->adjust_bezt->f1 |= SELECT;
1273                 slide_data->other_bezt->f3 |= SELECT;
1274         }
1275         mask_layer->act_spline = spline;
1276         mask_layer->act_point = point;
1277         ED_mask_select_flush_all(mask);
1278
1279         return slide_data;
1280 }
1281
1282 static int slide_spline_curvature_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1283 {
1284         Mask *mask = CTX_data_edit_mask(C);
1285         SlideSplineCurvatureData *slide_data;
1286
1287         if (mask == NULL) {
1288                 return OPERATOR_PASS_THROUGH;
1289         }
1290
1291         /* Be sure we don't conflict with point slide here. */
1292         if (!slide_spline_curvature_check(C, event)) {
1293                 return OPERATOR_PASS_THROUGH;
1294         }
1295
1296         slide_data = slide_spline_curvature_customdata(C, event);
1297         if (slide_data != NULL) {
1298                 op->customdata = slide_data;
1299                 WM_event_add_modal_handler(C, op);
1300                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
1301                 return OPERATOR_RUNNING_MODAL;
1302         }
1303
1304         return OPERATOR_PASS_THROUGH;
1305 }
1306
1307 static void slide_spline_solve_P1(const float u,
1308                                   const float B[2],
1309                                   const float P0[2],
1310                                   const float P2[2],
1311                                   const float P3[2],
1312                                   float solution[2])
1313 {
1314         const float u2 = u * u, u3 = u * u * u;
1315         const float v = 1.0f - u;
1316         const float v2 = v * v, v3 = v * v * v;
1317         const float inv_divider = 1.0f / (3.0f * v2 * u);
1318         const float t = 3.0f * v * u2;
1319         solution[0] = -(v3 * P0[0] + t * P2[0] + u3 * P3[0] - B[0]) * inv_divider;
1320         solution[1] = -(v3 * P0[1] + t * P2[1] + u3 * P3[1] - B[1]) * inv_divider;
1321 }
1322
1323 static void slide_spline_solve_P2(const float u,
1324                                   const float B[2],
1325                                   const float P0[2],
1326                                   const float P1[2],
1327                                   const float P3[2],
1328                                   float solution[2])
1329 {
1330         const float u2 = u * u, u3 = u * u * u;
1331         const float v = 1.0f - u;
1332         const float v2 = v * v, v3 = v * v * v;
1333         const float inv_divider = 1.0f / (3.0f * v * u2);
1334         const float t = 3.0f * v2 * u;
1335         solution[0] = -(v3 * P0[0] + t * P1[0] + u3 * P3[0] - B[0]) * inv_divider;
1336         solution[1] = -(v3 * P0[1] + t * P1[1] + u3 * P3[1] - B[1]) * inv_divider;
1337 }
1338
1339 static int slide_spline_curvature_modal(bContext *C, wmOperator *op, const wmEvent *event)
1340 {
1341         Scene *scene = CTX_data_scene(C);
1342         const float margin = 0.2f;
1343         SlideSplineCurvatureData *slide_data = (SlideSplineCurvatureData *) op->customdata;
1344         float u = slide_data->u;
1345
1346         switch (event->type) {
1347                 case LEFTSHIFTKEY:
1348                 case RIGHTSHIFTKEY:
1349                 case LEFTCTRLKEY:
1350                 case RIGHTCTRLKEY:
1351                         if (ELEM(event->type, LEFTSHIFTKEY, RIGHTSHIFTKEY)) {
1352                                 slide_data->accurate = (event->val == KM_PRESS);
1353                         }
1354
1355                         if (ELEM(event->type, LEFTCTRLKEY, RIGHTCTRLKEY)) {
1356                                 if (event->val == KM_PRESS) {
1357                                         slide_data->adjust_bezt->h1 = slide_data->adjust_bezt->h2 = HD_FREE;
1358                                         if ((u > margin && u < 0.5f) || (u >= 0.5f && u < 1.0f - margin)) {
1359                                                 slide_data->other_bezt->h1 = slide_data->other_bezt->h2 = HD_FREE;
1360                                         }
1361                                 }
1362                                 else if (event->val == KM_RELEASE) {
1363                                         slide_data->adjust_bezt->h1 = slide_data->bezt_backup.h1;
1364                                         slide_data->adjust_bezt->h2 = slide_data->bezt_backup.h2;
1365                                         slide_data->other_bezt->h1 = slide_data->other_bezt_backup.h1;
1366                                         slide_data->other_bezt->h2 = slide_data->other_bezt_backup.h2;
1367                                 }
1368
1369                                 if (u < 0.5f) {
1370                                         copy_v2_v2(slide_data->adjust_bezt->vec[0], slide_data->bezt_backup.vec[0]);
1371                                         copy_v2_v2(slide_data->other_bezt->vec[2], slide_data->other_bezt_backup.vec[2]);
1372                                 }
1373                                 else {
1374                                         copy_v2_v2(slide_data->adjust_bezt->vec[2], slide_data->bezt_backup.vec[2]);
1375                                         copy_v2_v2(slide_data->other_bezt->vec[0], slide_data->other_bezt_backup.vec[0]);
1376                                 }
1377
1378                         }
1379
1380                         ATTR_FALLTHROUGH;  /* update CV position */
1381                 case MOUSEMOVE:
1382                 {
1383                         float B[2], mouse_coord[2], delta[2];
1384
1385                         /* Get coordinate spline is expected to go through. */
1386                         ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, mouse_coord);
1387                         sub_v2_v2v2(delta, mouse_coord, slide_data->prev_mouse_coord);
1388                         if (slide_data->accurate) {
1389                                 mul_v2_fl(delta, 0.2f);
1390                         }
1391                         add_v2_v2v2(B, slide_data->prev_spline_coord, delta);
1392                         copy_v2_v2(slide_data->prev_spline_coord, B);
1393                         copy_v2_v2(slide_data->prev_mouse_coord, mouse_coord);
1394
1395                         if (u < 0.5f) {
1396                                 float oldP2[2];
1397                                 bool need_restore_P2 = false;
1398
1399                                 if (u > margin) {
1400                                         float solution[2];
1401                                         float x = (u - margin) * 0.5f / (0.5f - margin);
1402                                         float weight =  (3 * x * x - 2 * x * x * x);
1403
1404                                         slide_spline_solve_P2(u, B,
1405                                                               slide_data->P0,
1406                                                               slide_data->P1,
1407                                                               slide_data->P3,
1408                                                               solution);
1409
1410                                         copy_v2_v2(oldP2, slide_data->P2);
1411                                         interp_v2_v2v2(slide_data->P2, slide_data->P2, solution, weight);
1412                                         copy_v2_v2(slide_data->other_bezt->vec[0], slide_data->P2);
1413                                         need_restore_P2 = true;
1414
1415                                         /* Tweak handle type in order to be able to apply the delta. */
1416                                         if (weight > 0.0f) {
1417                                                 if (slide_data->other_bezt->h1 <= HD_VECT) {
1418                                                         slide_data->other_bezt->h1 = HD_FREE;
1419                                                 }
1420                                         }
1421                                 }
1422
1423                                 slide_spline_solve_P1(u, B,
1424                                                       slide_data->P0,
1425                                                       slide_data->P2,
1426                                                       slide_data->P3,
1427                                                       slide_data->adjust_bezt->vec[2]);
1428
1429                                 if (need_restore_P2) {
1430                                         copy_v2_v2(slide_data->P2, oldP2);
1431                                 }
1432                         }
1433                         else {
1434                                 float oldP1[2];
1435                                 bool need_restore_P1 = false;
1436
1437                                 if (u < 1.0f - margin) {
1438                                         float solution[2];
1439                                         float x = ((1.0f - u) - margin) * 0.5f / (0.5f - margin);
1440                                         float weight = 3 * x * x - 2 * x * x * x;
1441
1442                                         slide_spline_solve_P1(u, B,
1443                                                               slide_data->P0,
1444                                                               slide_data->P2,
1445                                                               slide_data->P3,
1446                                                               solution);
1447
1448                                         copy_v2_v2(oldP1, slide_data->P1);
1449                                         interp_v2_v2v2(slide_data->P1, slide_data->P1, solution, weight);
1450                                         copy_v2_v2(slide_data->other_bezt->vec[2], slide_data->P1);
1451                                         need_restore_P1 = true;
1452
1453                                         /* Tweak handle type in order to be able to apply the delta. */
1454                                         if (weight > 0.0f) {
1455                                                 if (slide_data->other_bezt->h2 <= HD_VECT) {
1456                                                         slide_data->other_bezt->h2 = HD_FREE;
1457                                                 }
1458                                         }
1459                                 }
1460
1461                                 slide_spline_solve_P2(u, B,
1462                                                       slide_data->P0,
1463                                                       slide_data->P1,
1464                                                       slide_data->P3,
1465                                                       slide_data->adjust_bezt->vec[0]);
1466
1467                                 if (need_restore_P1) {
1468                                         copy_v2_v2(slide_data->P1, oldP1);
1469                                 }
1470                         }
1471
1472                         WM_event_add_notifier(C, NC_MASK | NA_EDITED, slide_data->mask);
1473                         DEG_id_tag_update(&slide_data->mask->id, 0);
1474
1475                         break;
1476                 }
1477
1478                 case LEFTMOUSE:
1479                 case RIGHTMOUSE:
1480                         if (event->type == slide_data->event_invoke_type && event->val == KM_RELEASE) {
1481                                 /* dont key sliding feather uw's */
1482                                 if (IS_AUTOKEY_ON(scene)) {
1483                                         ED_mask_layer_shape_auto_key(slide_data->mask_layer, CFRA);
1484                                 }
1485
1486                                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, slide_data->mask);
1487                                 DEG_id_tag_update(&slide_data->mask->id, 0);
1488
1489                                 free_slide_spline_curvature_data(slide_data); /* keep this last! */
1490                                 return OPERATOR_FINISHED;
1491                         }
1492
1493                         break;
1494
1495                 case ESCKEY:
1496                         cancel_slide_spline_curvature(slide_data);
1497
1498                         WM_event_add_notifier(C, NC_MASK | NA_EDITED, slide_data->mask);
1499                         DEG_id_tag_update(&slide_data->mask->id, 0);
1500
1501                         free_slide_spline_curvature_data(op->customdata); /* keep this last! */
1502                         return OPERATOR_CANCELLED;
1503         }
1504
1505         return OPERATOR_RUNNING_MODAL;
1506 }
1507
1508 void MASK_OT_slide_spline_curvature(wmOperatorType *ot)
1509 {
1510         /* identifiers */
1511         ot->name = "Slide Spline Curvature";
1512         ot->description = "Slide a point on the spline to define it's curvature";
1513         ot->idname = "MASK_OT_slide_spline_curvature";
1514
1515         /* api callbacks */
1516         ot->invoke = slide_spline_curvature_invoke;
1517         ot->modal = slide_spline_curvature_modal;
1518         ot->poll = ED_operator_mask;
1519
1520         /* flags */
1521         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1522 }
1523
1524 /******************** toggle cyclic *********************/
1525
1526 static int cyclic_toggle_exec(bContext *C, wmOperator *UNUSED(op))
1527 {
1528         Mask *mask = CTX_data_edit_mask(C);
1529         MaskLayer *masklay;
1530
1531         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
1532                 MaskSpline *spline;
1533
1534                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
1535                         continue;
1536                 }
1537
1538                 for (spline = masklay->splines.first; spline; spline = spline->next) {
1539                         if (ED_mask_spline_select_check(spline)) {
1540                                 spline->flag ^= MASK_SPLINE_CYCLIC;
1541                         }
1542                 }
1543         }
1544
1545         DEG_id_tag_update(&mask->id, 0);
1546         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
1547
1548         return OPERATOR_FINISHED;
1549 }
1550
1551 void MASK_OT_cyclic_toggle(wmOperatorType *ot)
1552 {
1553         /* identifiers */
1554         ot->name = "Toggle Cyclic";
1555         ot->description = "Toggle cyclic for selected splines";
1556         ot->idname = "MASK_OT_cyclic_toggle";
1557
1558         /* api callbacks */
1559         ot->exec = cyclic_toggle_exec;
1560         ot->poll = ED_maskedit_mask_poll;
1561
1562         /* flags */
1563         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1564 }
1565
1566 /******************** delete *********************/
1567
1568 static void delete_feather_points(MaskSplinePoint *point)
1569 {
1570         int i, count = 0;
1571
1572         if (!point->tot_uw)
1573                 return;
1574
1575         for (i = 0; i < point->tot_uw; i++) {
1576                 if ((point->uw[i].flag & SELECT) == 0)
1577                         count++;
1578         }
1579
1580         if (count == 0) {
1581                 MEM_freeN(point->uw);
1582                 point->uw = NULL;
1583                 point->tot_uw = 0;
1584         }
1585         else {
1586                 MaskSplinePointUW *new_uw;
1587                 int j = 0;
1588
1589                 new_uw = MEM_callocN(count * sizeof(MaskSplinePointUW), "new mask uw points");
1590
1591                 for (i = 0; i < point->tot_uw; i++) {
1592                         if ((point->uw[i].flag & SELECT) == 0) {
1593                                 new_uw[j++] = point->uw[i];
1594                         }
1595                 }
1596
1597                 MEM_freeN(point->uw);
1598
1599                 point->uw = new_uw;
1600                 point->tot_uw = count;
1601         }
1602 }
1603
1604 static int delete_exec(bContext *C, wmOperator *UNUSED(op))
1605 {
1606         Scene *scene = CTX_data_scene(C);
1607         Mask *mask = CTX_data_edit_mask(C);
1608         MaskLayer *masklay;
1609         bool changed = false;
1610
1611         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
1612                 MaskSpline *spline;
1613                 int mask_layer_shape_ofs = 0;
1614
1615                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
1616                         continue;
1617                 }
1618
1619                 spline = masklay->splines.first;
1620
1621                 while (spline) {
1622                         const int tot_point_orig = spline->tot_point;
1623                         int i, count = 0;
1624                         MaskSpline *next_spline = spline->next;
1625
1626                         /* count unselected points */
1627                         for (i = 0; i < spline->tot_point; i++) {
1628                                 MaskSplinePoint *point = &spline->points[i];
1629
1630                                 if (!MASKPOINT_ISSEL_ANY(point))
1631                                         count++;
1632                         }
1633
1634                         if (count == 0) {
1635                                 /* delete the whole spline */
1636                                 BLI_remlink(&masklay->splines, spline);
1637                                 BKE_mask_spline_free(spline);
1638
1639                                 if (spline == masklay->act_spline) {
1640                                         masklay->act_spline = NULL;
1641                                         masklay->act_point = NULL;
1642                                 }
1643
1644                                 BKE_mask_layer_shape_changed_remove(masklay, mask_layer_shape_ofs, tot_point_orig);
1645                         }
1646                         else {
1647                                 MaskSplinePoint *new_points;
1648                                 int j;
1649
1650                                 new_points = MEM_callocN(count * sizeof(MaskSplinePoint), "deleteMaskPoints");
1651
1652                                 for (i = 0, j = 0; i < tot_point_orig; i++) {
1653                                         MaskSplinePoint *point = &spline->points[i];
1654
1655                                         if (!MASKPOINT_ISSEL_ANY(point)) {
1656                                                 if (point == masklay->act_point)
1657                                                         masklay->act_point = &new_points[j];
1658
1659                                                 delete_feather_points(point);
1660
1661                                                 new_points[j] = *point;
1662                                                 j++;
1663                                         }
1664                                         else {
1665                                                 if (point == masklay->act_point)
1666                                                         masklay->act_point = NULL;
1667
1668                                                 BKE_mask_point_free(point);
1669                                                 spline->tot_point--;
1670
1671                                                 BKE_mask_layer_shape_changed_remove(masklay, mask_layer_shape_ofs + j, 1);
1672                                         }
1673                                 }
1674
1675                                 mask_layer_shape_ofs += spline->tot_point;
1676
1677                                 MEM_freeN(spline->points);
1678                                 spline->points = new_points;
1679
1680                                 ED_mask_select_flush_all(mask);
1681                         }
1682
1683                         changed = true;
1684                         spline = next_spline;
1685                 }
1686
1687                 /* not essential but confuses users when there are keys with no data!
1688                  * assume if they delete all data from the layer they also dont care about keys */
1689                 if (BLI_listbase_is_empty(&masklay->splines)) {
1690                         BKE_mask_layer_free_shapes(masklay);
1691                 }
1692         }
1693
1694         if (!changed) {
1695                 return OPERATOR_CANCELLED;
1696         }
1697
1698         /* TODO: only update edited splines */
1699         BKE_mask_update_display(mask, CFRA);
1700
1701         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
1702
1703         return OPERATOR_FINISHED;
1704 }
1705
1706 void MASK_OT_delete(wmOperatorType *ot)
1707 {
1708         /* identifiers */
1709         ot->name = "Delete";
1710         ot->description = "Delete selected control points or splines";
1711         ot->idname = "MASK_OT_delete";
1712
1713         /* api callbacks */
1714         ot->invoke = WM_operator_confirm;
1715         ot->exec = delete_exec;
1716         ot->poll = ED_maskedit_mask_poll;
1717
1718         /* flags */
1719         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1720 }
1721
1722 /* *** switch direction *** */
1723 static int mask_switch_direction_exec(bContext *C, wmOperator *UNUSED(op))
1724 {
1725         Scene *scene = CTX_data_scene(C);
1726         Mask *mask = CTX_data_edit_mask(C);
1727         MaskLayer *masklay;
1728
1729         bool changed = false;
1730
1731         /* do actual selection */
1732         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
1733                 MaskSpline *spline;
1734                 bool changed_layer = false;
1735
1736                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
1737                         continue;
1738                 }
1739
1740                 for (spline = masklay->splines.first; spline; spline = spline->next) {
1741                         if (ED_mask_spline_select_check(spline)) {
1742                                 BKE_mask_spline_direction_switch(masklay, spline);
1743                                 changed = true;
1744                                 changed_layer = true;
1745                         }
1746                 }
1747
1748                 if (changed_layer) {
1749                         if (IS_AUTOKEY_ON(scene)) {
1750                                 ED_mask_layer_shape_auto_key(masklay, CFRA);
1751                         }
1752                 }
1753         }
1754
1755         if (changed) {
1756                 /* TODO: only update this spline */
1757                 BKE_mask_update_display(mask, CFRA);
1758
1759                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
1760                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
1761
1762                 return OPERATOR_FINISHED;
1763         }
1764
1765         return OPERATOR_CANCELLED;
1766 }
1767
1768 void MASK_OT_switch_direction(wmOperatorType *ot)
1769 {
1770         /* identifiers */
1771         ot->name = "Switch Direction";
1772         ot->description = "Switch direction of selected splines";
1773         ot->idname = "MASK_OT_switch_direction";
1774
1775         /* api callbacks */
1776         ot->exec = mask_switch_direction_exec;
1777         ot->poll = ED_maskedit_mask_poll;
1778
1779         /* flags */
1780         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1781 }
1782
1783
1784 /* *** recalc normals *** */
1785 static int mask_normals_make_consistent_exec(bContext *C, wmOperator *UNUSED(op))
1786 {
1787         Scene *scene = CTX_data_scene(C);
1788         Mask *mask = CTX_data_edit_mask(C);
1789         MaskLayer *masklay;
1790         int i;
1791
1792         bool changed = false;
1793
1794         /* do actual selection */
1795         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
1796                 MaskSpline *spline;
1797                 bool changed_layer = false;
1798
1799                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
1800                         continue;
1801                 }
1802
1803                 for (spline = masklay->splines.first; spline; spline = spline->next) {
1804                         for (i = 0; i < spline->tot_point; i++) {
1805                                 MaskSplinePoint *point = &spline->points[i];
1806
1807                                 if (MASKPOINT_ISSEL_ANY(point)) {
1808                                         BKE_mask_calc_handle_point_auto(spline, point, false);
1809                                         changed = true;
1810                                         changed_layer = true;
1811                                 }
1812                         }
1813                 }
1814
1815                 if (changed_layer) {
1816                         if (IS_AUTOKEY_ON(scene)) {
1817                                 ED_mask_layer_shape_auto_key(masklay, CFRA);
1818                         }
1819                 }
1820         }
1821
1822         if (changed) {
1823                 /* TODO: only update this spline */
1824                 BKE_mask_update_display(mask, CFRA);
1825
1826                 WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask);
1827                 WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
1828
1829                 return OPERATOR_FINISHED;
1830         }
1831
1832         return OPERATOR_CANCELLED;
1833 }
1834
1835 /* named to match mesh recalc normals */
1836 void MASK_OT_normals_make_consistent(wmOperatorType *ot)
1837 {
1838         /* identifiers */
1839         ot->name = "Recalc Normals";
1840         ot->description = "Re-calculate the direction of selected handles";
1841         ot->idname = "MASK_OT_normals_make_consistent";
1842
1843         /* api callbacks */
1844         ot->exec = mask_normals_make_consistent_exec;
1845         ot->poll = ED_maskedit_mask_poll;
1846
1847         /* flags */
1848         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1849 }
1850
1851
1852 /******************** set handle type *********************/
1853
1854 static int set_handle_type_exec(bContext *C, wmOperator *op)
1855 {
1856         Mask *mask = CTX_data_edit_mask(C);
1857         MaskLayer *masklay;
1858         int handle_type = RNA_enum_get(op->ptr, "type");
1859
1860         bool changed = false;
1861
1862         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
1863                 MaskSpline *spline;
1864                 int i;
1865
1866                 if (masklay->restrictflag & (MASK_RESTRICT_VIEW | MASK_RESTRICT_SELECT)) {
1867                         continue;
1868                 }
1869
1870                 for (spline = masklay->splines.first; spline; spline = spline->next) {
1871                         for (i = 0; i < spline->tot_point; i++) {
1872                                 MaskSplinePoint *point = &spline->points[i];
1873
1874                                 if (MASKPOINT_ISSEL_ANY(point)) {
1875                                         BezTriple *bezt = &point->bezt;
1876
1877                                         if (bezt->f2 & SELECT) {
1878                                                 bezt->h1 = handle_type;
1879                                                 bezt->h2 = handle_type;
1880                                         }
1881                                         else {
1882                                                 if (bezt->f1 & SELECT) {
1883                                                         bezt->h1 = handle_type;
1884                                                 }
1885                                                 if (bezt->f3 & SELECT) {
1886                                                         bezt->h2 = handle_type;
1887                                                 }
1888                                         }
1889
1890                                         if (handle_type == HD_ALIGN) {
1891                                                 float vec[3];
1892                                                 sub_v3_v3v3(vec, bezt->vec[0], bezt->vec[1]);
1893                                                 add_v3_v3v3(bezt->vec[2], bezt->vec[1], vec);
1894                                         }
1895
1896                                         changed = true;
1897                                 }
1898                         }
1899                 }
1900         }
1901
1902         if (changed) {
1903                 WM_event_add_notifier(C, NC_MASK | ND_DATA, mask);
1904                 DEG_id_tag_update(&mask->id, 0);
1905
1906                 return OPERATOR_FINISHED;
1907         }
1908         return OPERATOR_CANCELLED;
1909 }
1910
1911 void MASK_OT_handle_type_set(wmOperatorType *ot)
1912 {
1913         static EnumPropertyItem editcurve_handle_type_items[] = {
1914                 {HD_AUTO, "AUTO", 0, "Auto", ""},
1915                 {HD_VECT, "VECTOR", 0, "Vector", ""},
1916                 {HD_ALIGN, "ALIGNED", 0, "Aligned Single", ""},
1917                 {HD_ALIGN_DOUBLESIDE, "ALIGNED_DOUBLESIDE", 0, "Aligned", ""},
1918                 {HD_FREE, "FREE", 0, "Free", ""},
1919                 {0, NULL, 0, NULL, NULL}
1920         };
1921
1922         /* identifiers */
1923         ot->name = "Set Handle Type";
1924         ot->description = "Set type of handles for selected control points";
1925         ot->idname = "MASK_OT_handle_type_set";
1926
1927         /* api callbacks */
1928         ot->invoke = WM_menu_invoke;
1929         ot->exec = set_handle_type_exec;
1930         ot->poll = ED_maskedit_mask_poll;
1931
1932         /* flags */
1933         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1934
1935         /* properties */
1936         ot->prop = RNA_def_enum(ot->srna, "type", editcurve_handle_type_items, 1, "Type", "Spline type");
1937 }
1938
1939
1940 /* ********* clear/set restrict view *********/
1941 static int mask_hide_view_clear_exec(bContext *C, wmOperator *UNUSED(op))
1942 {
1943         Mask *mask = CTX_data_edit_mask(C);
1944         MaskLayer *masklay;
1945         bool changed = false;
1946
1947         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
1948
1949                 if (masklay->restrictflag & OB_RESTRICT_VIEW) {
1950                         ED_mask_layer_select_set(masklay, true);
1951                         masklay->restrictflag &= ~OB_RESTRICT_VIEW;
1952                         changed = true;
1953                 }
1954         }
1955
1956         if (changed) {
1957                 WM_event_add_notifier(C, NC_MASK | ND_DRAW, mask);
1958                 DEG_id_tag_update(&mask->id, 0);
1959
1960                 return OPERATOR_FINISHED;
1961         }
1962         else {
1963                 return OPERATOR_CANCELLED;
1964         }
1965 }
1966
1967 void MASK_OT_hide_view_clear(wmOperatorType *ot)
1968 {
1969
1970         /* identifiers */
1971         ot->name = "Clear Restrict View";
1972         ot->description = "Reveal the layer by setting the hide flag";
1973         ot->idname = "MASK_OT_hide_view_clear";
1974
1975         /* api callbacks */
1976         ot->exec = mask_hide_view_clear_exec;
1977         ot->poll = ED_maskedit_mask_poll;
1978
1979         /* flags */
1980         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1981 }
1982
1983 static int mask_hide_view_set_exec(bContext *C, wmOperator *op)
1984 {
1985         Mask *mask = CTX_data_edit_mask(C);
1986         MaskLayer *masklay;
1987         const bool unselected = RNA_boolean_get(op->ptr, "unselected");
1988         bool changed = false;
1989
1990         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
1991
1992                 if (masklay->restrictflag & MASK_RESTRICT_SELECT) {
1993                         continue;
1994                 }
1995
1996                 if (!unselected) {
1997                         if (ED_mask_layer_select_check(masklay)) {
1998                                 ED_mask_layer_select_set(masklay, false);
1999
2000                                 masklay->restrictflag |= OB_RESTRICT_VIEW;
2001                                 changed = true;
2002                                 if (masklay == BKE_mask_layer_active(mask)) {
2003                                         BKE_mask_layer_active_set(mask, NULL);
2004                                 }
2005                         }
2006                 }
2007                 else {
2008                         if (!ED_mask_layer_select_check(masklay)) {
2009                                 masklay->restrictflag |= OB_RESTRICT_VIEW;
2010                                 changed = true;
2011                                 if (masklay == BKE_mask_layer_active(mask)) {
2012                                         BKE_mask_layer_active_set(mask, NULL);
2013                                 }
2014                         }
2015                 }
2016         }
2017
2018         if (changed) {
2019                 WM_event_add_notifier(C, NC_MASK | ND_DRAW, mask);
2020                 DEG_id_tag_update(&mask->id, 0);
2021
2022                 return OPERATOR_FINISHED;
2023         }
2024         else {
2025                 return OPERATOR_CANCELLED;
2026         }
2027 }
2028
2029 void MASK_OT_hide_view_set(wmOperatorType *ot)
2030 {
2031         /* identifiers */
2032         ot->name = "Set Restrict View";
2033         ot->description = "Hide the layer by setting the hide flag";
2034         ot->idname = "MASK_OT_hide_view_set";
2035
2036         /* api callbacks */
2037         ot->exec = mask_hide_view_set_exec;
2038         ot->poll = ED_maskedit_mask_poll;
2039
2040         /* flags */
2041         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2042
2043         RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Hide unselected rather than selected layers");
2044 }
2045
2046
2047 static int mask_feather_weight_clear_exec(bContext *C, wmOperator *UNUSED(op))
2048 {
2049         Scene *scene = CTX_data_scene(C);
2050         Mask *mask = CTX_data_edit_mask(C);
2051         MaskLayer *masklay;
2052         bool changed = false;
2053         int i;
2054
2055         for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
2056                 MaskSpline *spline;
2057
2058                 if (masklay->restrictflag & (MASK_RESTRICT_SELECT | MASK_RESTRICT_VIEW)) {
2059                         continue;
2060                 }
2061
2062                 for (spline = masklay->splines.first; spline; spline = spline->next) {
2063                         for (i = 0; i < spline->tot_point; i++) {
2064                                 MaskSplinePoint *point = &spline->points[i];
2065
2066                                 if (MASKPOINT_ISSEL_ANY(point)) {
2067                                         BezTriple *bezt = &point->bezt;
2068                                         bezt->weight = 0.0f;
2069                                         changed = true;
2070                                 }
2071                         }
2072                 }
2073         }
2074
2075         if (changed) {
2076                 /* TODO: only update edited splines */
2077                 BKE_mask_update_display(mask, CFRA);
2078
2079                 WM_event_add_notifier(C, NC_MASK | ND_DRAW, mask);
2080                 DEG_id_tag_update(&mask->id, 0);
2081
2082                 return OPERATOR_FINISHED;
2083         }
2084         else {
2085                 return OPERATOR_CANCELLED;
2086         }
2087 }
2088
2089 void MASK_OT_feather_weight_clear(wmOperatorType *ot)
2090 {
2091         /* identifiers */
2092         ot->name = "Clear Feather Weight";
2093         ot->description = "Reset the feather weight to zero";
2094         ot->idname = "MASK_OT_feather_weight_clear";
2095
2096         /* api callbacks */
2097         ot->exec = mask_feather_weight_clear_exec;
2098         ot->poll = ED_maskedit_mask_poll;
2099
2100         /* flags */
2101         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2102 }
2103
2104 /******************** move mask layer operator *********************/
2105
2106 static int mask_layer_move_poll(bContext *C)
2107 {
2108         if (ED_maskedit_mask_poll(C)) {
2109                 Mask *mask = CTX_data_edit_mask(C);
2110
2111                 return mask->masklay_tot > 0;
2112         }
2113
2114         return false;
2115 }
2116
2117 static int mask_layer_move_exec(bContext *C, wmOperator *op)
2118 {
2119         Mask *mask = CTX_data_edit_mask(C);
2120         MaskLayer *mask_layer = BLI_findlink(&mask->masklayers, mask->masklay_act);
2121         MaskLayer *mask_layer_other;
2122         int direction = RNA_enum_get(op->ptr, "direction");
2123
2124         if (!mask_layer)
2125                 return OPERATOR_CANCELLED;
2126
2127         if (direction == -1) {
2128                 mask_layer_other = mask_layer->prev;
2129
2130                 if (!mask_layer_other)
2131                         return OPERATOR_CANCELLED;
2132
2133                 BLI_remlink(&mask->masklayers, mask_layer);
2134                 BLI_insertlinkbefore(&mask->masklayers, mask_layer_other, mask_layer);
2135                 mask->masklay_act--;
2136         }
2137         else if (direction == 1) {
2138                 mask_layer_other = mask_layer->next;
2139
2140                 if (!mask_layer_other)
2141                         return OPERATOR_CANCELLED;
2142
2143                 BLI_remlink(&mask->masklayers, mask_layer);
2144                 BLI_insertlinkafter(&mask->masklayers, mask_layer_other, mask_layer);
2145                 mask->masklay_act++;
2146         }
2147
2148         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
2149
2150         return OPERATOR_FINISHED;
2151 }
2152
2153 void MASK_OT_layer_move(wmOperatorType *ot)
2154 {
2155         static EnumPropertyItem direction_items[] = {
2156                 {-1, "UP", 0, "Up", ""},
2157                 {1, "DOWN", 0, "Down", ""},
2158                 {0, NULL, 0, NULL, NULL}
2159         };
2160
2161         /* identifiers */
2162         ot->name = "Move Layer";
2163         ot->description = "Move the active layer up/down in the list";
2164         ot->idname = "MASK_OT_layer_move";
2165
2166         /* api callbacks */
2167         ot->exec = mask_layer_move_exec;
2168         ot->poll = mask_layer_move_poll;
2169
2170         /* flags */
2171         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2172
2173         /* properties */
2174         RNA_def_enum(ot->srna, "direction", direction_items, 0, "Direction", "Direction to move the active layer");
2175 }
2176
2177 /******************** duplicate *********************/
2178
2179 static int mask_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
2180 {
2181         Scene *scene = CTX_data_scene(C);
2182         Mask *mask = CTX_data_edit_mask(C);
2183         MaskLayer *mask_layer;
2184
2185         for (mask_layer = mask->masklayers.first;
2186              mask_layer;
2187              mask_layer = mask_layer->next)
2188         {
2189                 MaskSpline *spline;
2190
2191                 for (spline = mask_layer->splines.last;
2192                      spline;
2193                      spline = spline->prev)
2194                 {
2195                         MaskSplinePoint *point = spline->points;
2196                         int i = 0;
2197                         while (i < spline->tot_point) {
2198                                 int start = i, end = -1;
2199                                 /* Find next selected segment. */
2200                                 while (MASKPOINT_ISSEL_ANY(point)) {
2201                                         BKE_mask_point_select_set(point, false);
2202                                         end = i;
2203                                         if (i >= spline->tot_point - 1) {
2204                                                 break;
2205                                         }
2206                                         i++;
2207                                         point++;
2208                                 }
2209                                 if (end >= start) {
2210                                         int tot_point;
2211                                         int tot_point_shape_start = 0;
2212                                         MaskSpline *new_spline = BKE_mask_spline_add(mask_layer);
2213                                         MaskSplinePoint *new_point;
2214                                         int b;
2215
2216                                         /* BKE_mask_spline_add might allocate the points, need to free them in this case. */
2217                                         if (new_spline->points) {
2218                                                 MEM_freeN(new_spline->points);
2219                                         }
2220
2221                                         /* Copy options from old spline. */
2222                                         new_spline->flag = spline->flag;
2223                                         new_spline->offset_mode = spline->offset_mode;
2224                                         new_spline->weight_interp = spline->weight_interp;
2225                                         new_spline->parent = spline->parent;
2226
2227                                         /* Allocate new points and copy them from old spline. */
2228                                         new_spline->tot_point = end - start + 1;
2229                                         new_spline->points = MEM_mallocN(sizeof(MaskSplinePoint) * new_spline->tot_point,
2230                                                                          "duplicated mask points");
2231
2232                                         memcpy(new_spline->points, spline->points + start,
2233                                                new_spline->tot_point * sizeof(MaskSplinePoint));
2234
2235                                         tot_point = new_spline->tot_point;
2236
2237                                         /* animation requires points added one by one */
2238                                         if (mask_layer->splines_shapes.first) {
2239                                                 new_spline->tot_point = 0;
2240                                                 tot_point_shape_start = BKE_mask_layer_shape_spline_to_index(mask_layer, new_spline);
2241                                         }
2242
2243                                         /* Select points and duplicate their UWs (if needed). */
2244                                         for (b = 0, new_point = new_spline->points;
2245                                              b < tot_point;
2246                                              b++, new_point++)
2247                                         {
2248                                                 if (new_point->uw) {
2249                                                         new_point->uw = MEM_dupallocN(new_point->uw);
2250                                                 }
2251                                                 BKE_mask_point_select_set(new_point, true);
2252
2253
2254                                                 if (mask_layer->splines_shapes.first) {
2255                                                         new_spline->tot_point++;
2256                                                         BKE_mask_layer_shape_changed_add(mask_layer, tot_point_shape_start + b, true, false);
2257                                                 }
2258                                         }
2259
2260                                         /* Clear cyclic flag if we didn't copy the whole spline. */
2261                                         if (new_spline->flag & MASK_SPLINE_CYCLIC) {
2262                                                 if (start != 0 || end != spline->tot_point - 1) {
2263                                                         new_spline->flag &= ~MASK_SPLINE_CYCLIC;
2264                                                 }
2265                                         }
2266
2267                                         /* Flush selection to splines. */
2268                                         new_spline->flag |= SELECT;
2269                                         spline->flag &= ~SELECT;
2270
2271                                         mask_layer->act_spline = new_spline;
2272                                 }
2273                                 i++;
2274                                 point++;
2275                         }
2276                 }
2277         }
2278
2279         /* TODO: only update edited splines */
2280         BKE_mask_update_display(mask, CFRA);
2281
2282         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
2283
2284         return OPERATOR_FINISHED;
2285 }
2286
2287 void MASK_OT_duplicate(wmOperatorType *ot)
2288 {
2289         /* identifiers */
2290         ot->name = "Duplicate Mask";
2291         ot->description = "Duplicate selected control points and segments between them";
2292         ot->idname = "MASK_OT_duplicate";
2293
2294         /* api callbacks */
2295         ot->exec = mask_duplicate_exec;
2296         ot->poll = ED_maskedit_mask_poll;
2297
2298         /* flags */
2299         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2300 }
2301
2302 /********************** copy splines to clipboard operator *********************/
2303
2304 static int copy_splines_exec(bContext *C, wmOperator *UNUSED(op))
2305 {
2306         Mask *mask = CTX_data_edit_mask(C);
2307         MaskLayer *mask_layer = BKE_mask_layer_active(mask);
2308
2309         if (mask_layer == NULL) {
2310                 return OPERATOR_CANCELLED;
2311         }
2312
2313         BKE_mask_clipboard_copy_from_layer(mask_layer);
2314
2315         return OPERATOR_FINISHED;
2316 }
2317
2318 void MASK_OT_copy_splines(wmOperatorType *ot)
2319 {
2320         /* identifiers */
2321         ot->name = "Copy Splines";
2322         ot->description = "Copy selected splines to clipboard";
2323         ot->idname = "MASK_OT_copy_splines";
2324
2325         /* api callbacks */
2326         ot->exec = copy_splines_exec;
2327         ot->poll = ED_maskedit_mask_poll;
2328
2329         /* flags */
2330         ot->flag = OPTYPE_REGISTER;
2331 }
2332
2333 /********************** paste tracks from clipboard operator *********************/
2334
2335 static int paste_splines_poll(bContext *C)
2336 {
2337         if (ED_maskedit_mask_poll(C)) {
2338                 return BKE_mask_clipboard_is_empty() == false;
2339         }
2340
2341         return 0;
2342 }
2343
2344 static int paste_splines_exec(bContext *C, wmOperator *UNUSED(op))
2345 {
2346         Scene *scene = CTX_data_scene(C);
2347         Mask *mask = CTX_data_edit_mask(C);
2348         MaskLayer *mask_layer = BKE_mask_layer_active(mask);
2349
2350         if (mask_layer == NULL) {
2351                 mask_layer = BKE_mask_layer_new(mask, "");
2352         }
2353
2354         BKE_mask_clipboard_paste_to_layer(CTX_data_main(C), mask_layer);
2355
2356         /* TODO: only update edited splines */
2357         BKE_mask_update_display(mask, CFRA);
2358
2359         WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask);
2360
2361         return OPERATOR_FINISHED;
2362 }
2363
2364 void MASK_OT_paste_splines(wmOperatorType *ot)
2365 {
2366         /* identifiers */
2367         ot->name = "Paste Splines";
2368         ot->description = "Paste splines from clipboard";
2369         ot->idname = "MASK_OT_paste_splines";
2370
2371         /* api callbacks */
2372         ot->exec = paste_splines_exec;
2373         ot->poll = paste_splines_poll;
2374
2375         /* flags */
2376         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2377 }