Cleanup: style, use braces for editors
[blender.git] / source / blender / editors / space_clip / clip_graph_ops.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2011 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup spclip
22  */
23
24 #include "DNA_scene_types.h"
25
26 #include "BLI_utildefines.h"
27 #include "BLI_math.h"
28 #include "BLI_rect.h"
29
30 #include "BKE_context.h"
31 #include "BKE_tracking.h"
32
33 #include "DEG_depsgraph.h"
34
35 #include "WM_api.h"
36 #include "WM_types.h"
37
38 #include "ED_screen.h"
39 #include "ED_select_utils.h"
40 #include "ED_clip.h"
41
42 #include "RNA_access.h"
43 #include "RNA_define.h"
44
45 #include "UI_view2d.h"
46
47 #include "clip_intern.h"  // own include
48
49 /******************** common graph-editing utilities ********************/
50
51 static bool ED_space_clip_graph_poll(bContext *C)
52 {
53   if (ED_space_clip_tracking_poll(C)) {
54     SpaceClip *sc = CTX_wm_space_clip(C);
55
56     return sc->view == SC_VIEW_GRAPH;
57   }
58
59   return false;
60 }
61
62 static bool clip_graph_knots_poll(bContext *C)
63 {
64   if (ED_space_clip_graph_poll(C)) {
65     SpaceClip *sc = CTX_wm_space_clip(C);
66
67     return (sc->flag & SC_SHOW_GRAPH_TRACKS_MOTION) != 0;
68   }
69   return false;
70 }
71
72 typedef struct {
73   int action;
74 } SelectUserData;
75
76 static void toggle_selection_cb(void *userdata, MovieTrackingMarker *marker)
77 {
78   SelectUserData *data = (SelectUserData *)userdata;
79
80   switch (data->action) {
81     case SEL_SELECT:
82       marker->flag |= MARKER_GRAPH_SEL;
83       break;
84     case SEL_DESELECT:
85       marker->flag &= ~MARKER_GRAPH_SEL;
86       break;
87     case SEL_INVERT:
88       marker->flag ^= MARKER_GRAPH_SEL;
89       break;
90   }
91 }
92
93 /******************** mouse select operator ********************/
94
95 typedef struct {
96   int coord;     /* coordinate index of found entuty (0 = X-axis, 1 = Y-axis) */
97   bool has_prev; /* if there's valid coordinate of previous point of curve segment */
98
99   float min_dist_sq, /* minimal distance between mouse and currently found entity */
100       mouse_co[2],   /* mouse coordinate */
101       prev_co[2],    /* coordinate of previeous point of segment */
102       min_co[2];     /* coordinate of entity with minimal distance */
103
104   MovieTrackingTrack *track;   /* nearest found track */
105   MovieTrackingMarker *marker; /* nearest found marker */
106 } MouseSelectUserData;
107
108 static void find_nearest_tracking_segment_cb(void *userdata,
109                                              MovieTrackingTrack *track,
110                                              MovieTrackingMarker *UNUSED(marker),
111                                              int coord,
112                                              int scene_framenr,
113                                              float val)
114 {
115   MouseSelectUserData *data = userdata;
116   float co[2] = {scene_framenr, val};
117
118   if (data->has_prev) {
119     float dist_sq = dist_squared_to_line_segment_v2(data->mouse_co, data->prev_co, co);
120
121     if (data->track == NULL || dist_sq < data->min_dist_sq) {
122       data->track = track;
123       data->min_dist_sq = dist_sq;
124       data->coord = coord;
125       copy_v2_v2(data->min_co, co);
126     }
127   }
128
129   data->has_prev = true;
130   copy_v2_v2(data->prev_co, co);
131 }
132
133 static void find_nearest_tracking_segment_end_cb(void *userdata, int UNUSED(coord))
134 {
135   MouseSelectUserData *data = userdata;
136
137   data->has_prev = false;
138 }
139
140 static void find_nearest_tracking_knot_cb(void *userdata,
141                                           MovieTrackingTrack *track,
142                                           MovieTrackingMarker *marker,
143                                           int coord,
144                                           int scene_framenr,
145                                           float val)
146 {
147   MouseSelectUserData *data = userdata;
148   float mdiff[2] = {scene_framenr - data->mouse_co[0], val - data->mouse_co[1]};
149   float dist_sq = len_squared_v2(mdiff);
150
151   if (data->marker == NULL || dist_sq < data->min_dist_sq) {
152     float co[2] = {scene_framenr, val};
153
154     data->track = track;
155     data->marker = marker;
156     data->min_dist_sq = dist_sq;
157     data->coord = coord;
158     copy_v2_v2(data->min_co, co);
159   }
160 }
161
162 static void mouse_select_init_data(MouseSelectUserData *userdata, const float co[2])
163 {
164   memset(userdata, 0, sizeof(MouseSelectUserData));
165   userdata->min_dist_sq = FLT_MAX;
166   copy_v2_v2(userdata->mouse_co, co);
167 }
168
169 static bool mouse_select_knot(bContext *C, float co[2], bool extend)
170 {
171   SpaceClip *sc = CTX_wm_space_clip(C);
172   MovieClip *clip = ED_space_clip_get_clip(sc);
173   ARegion *ar = CTX_wm_region(C);
174   View2D *v2d = &ar->v2d;
175   MovieTracking *tracking = &clip->tracking;
176   MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
177   static const int delta = 6;
178
179   if (act_track) {
180     MouseSelectUserData userdata;
181
182     mouse_select_init_data(&userdata, co);
183     clip_graph_tracking_values_iterate_track(
184         sc, act_track, &userdata, find_nearest_tracking_knot_cb, NULL, NULL);
185
186     if (userdata.marker) {
187       int x1, y1, x2, y2;
188
189       if (UI_view2d_view_to_region_clip(v2d, co[0], co[1], &x1, &y1) &&
190           UI_view2d_view_to_region_clip(v2d, userdata.min_co[0], userdata.min_co[1], &x2, &y2) &&
191           (abs(x2 - x1) <= delta && abs(y2 - y1) <= delta)) {
192         if (!extend) {
193           SelectUserData selectdata = {SEL_DESELECT};
194
195           clip_graph_tracking_iterate(sc,
196                                       (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
197                                       (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
198                                       &selectdata,
199                                       toggle_selection_cb);
200         }
201
202         if (userdata.coord == 0) {
203           if (extend && (userdata.marker->flag & MARKER_GRAPH_SEL_X) != 0) {
204             userdata.marker->flag &= ~MARKER_GRAPH_SEL_X;
205           }
206           else {
207             userdata.marker->flag |= MARKER_GRAPH_SEL_X;
208           }
209         }
210         else {
211           if (extend && (userdata.marker->flag & MARKER_GRAPH_SEL_Y) != 0) {
212             userdata.marker->flag &= ~MARKER_GRAPH_SEL_Y;
213           }
214           else {
215             userdata.marker->flag |= MARKER_GRAPH_SEL_Y;
216           }
217         }
218
219         return true;
220       }
221     }
222   }
223
224   return false;
225 }
226
227 static bool mouse_select_curve(bContext *C, float co[2], bool extend)
228 {
229   SpaceClip *sc = CTX_wm_space_clip(C);
230   MovieClip *clip = ED_space_clip_get_clip(sc);
231   MovieTracking *tracking = &clip->tracking;
232   MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
233   MouseSelectUserData userdata;
234
235   mouse_select_init_data(&userdata, co);
236   clip_graph_tracking_values_iterate(sc,
237                                      (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
238                                      (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
239                                      &userdata,
240                                      find_nearest_tracking_segment_cb,
241                                      NULL,
242                                      find_nearest_tracking_segment_end_cb);
243
244   if (userdata.track) {
245     if (extend) {
246       if (act_track == userdata.track) {
247         /* currently only single curve can be selected
248          * (selected curve represents active track) */
249         act_track = NULL;
250       }
251     }
252     else if (act_track != userdata.track) {
253       SelectUserData selectdata = {SEL_DESELECT};
254       MovieTrackingObject *object = BKE_tracking_object_get_active(tracking);
255
256       tracking->act_track = userdata.track;
257       if ((sc->flag & SC_SHOW_GRAPH_SEL_ONLY) == 0) {
258         ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object);
259         BKE_tracking_track_select(tracksbase, userdata.track, TRACK_AREA_ALL, false);
260       }
261
262       /* deselect all knots on newly selected curve */
263       clip_graph_tracking_iterate(sc,
264                                   (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
265                                   (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
266                                   &selectdata,
267                                   toggle_selection_cb);
268     }
269
270     return true;
271   }
272
273   return false;
274 }
275
276 static int mouse_select(bContext *C, float co[2], bool extend)
277 {
278   bool sel = false;
279
280   /* first try to select knot on selected curves */
281   sel = mouse_select_knot(C, co, extend);
282
283   if (!sel) {
284     /* if there's no close enough knot to mouse osition, select nearest curve */
285     sel = mouse_select_curve(C, co, extend);
286   }
287
288   if (sel) {
289     WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
290   }
291
292   return OPERATOR_FINISHED;
293 }
294
295 static int select_exec(bContext *C, wmOperator *op)
296 {
297   float co[2];
298   bool extend = RNA_boolean_get(op->ptr, "extend");
299
300   RNA_float_get_array(op->ptr, "location", co);
301
302   return mouse_select(C, co, extend);
303 }
304
305 static int select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
306 {
307   ARegion *ar = CTX_wm_region(C);
308   float co[2];
309
310   UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
311   RNA_float_set_array(op->ptr, "location", co);
312
313   return select_exec(C, op);
314 }
315
316 void CLIP_OT_graph_select(wmOperatorType *ot)
317 {
318   /* identifiers */
319   ot->name = "Select";
320   ot->description = "Select graph curves";
321   ot->idname = "CLIP_OT_graph_select";
322
323   /* api callbacks */
324   ot->exec = select_exec;
325   ot->invoke = select_invoke;
326   ot->poll = clip_graph_knots_poll;
327
328   /* flags */
329   ot->flag = OPTYPE_UNDO;
330
331   /* properties */
332   RNA_def_float_vector(ot->srna,
333                        "location",
334                        2,
335                        NULL,
336                        -FLT_MAX,
337                        FLT_MAX,
338                        "Location",
339                        "Mouse location to select nearest entity",
340                        -100.0f,
341                        100.0f);
342   RNA_def_boolean(ot->srna,
343                   "extend",
344                   0,
345                   "Extend",
346                   "Extend selection rather than clearing the existing selection");
347 }
348
349 /********************** box select operator *********************/
350
351 typedef struct BoxSelectuserData {
352   rctf rect;
353   bool select, extend, changed;
354 } BoxSelectuserData;
355
356 static void box_select_cb(void *userdata,
357                           MovieTrackingTrack *UNUSED(track),
358                           MovieTrackingMarker *marker,
359                           int coord,
360                           int scene_framenr,
361                           float val)
362 {
363   BoxSelectuserData *data = (BoxSelectuserData *)userdata;
364
365   if (BLI_rctf_isect_pt(&data->rect, scene_framenr, val)) {
366     int flag = 0;
367
368     if (coord == 0) {
369       flag = MARKER_GRAPH_SEL_X;
370     }
371     else {
372       flag = MARKER_GRAPH_SEL_Y;
373     }
374
375     if (data->select) {
376       marker->flag |= flag;
377     }
378     else {
379       marker->flag &= ~flag;
380     }
381     data->changed = true;
382   }
383   else if (!data->extend) {
384     marker->flag &= ~MARKER_GRAPH_SEL;
385   }
386 }
387
388 static int box_select_graph_exec(bContext *C, wmOperator *op)
389 {
390   SpaceClip *sc = CTX_wm_space_clip(C);
391   ARegion *ar = CTX_wm_region(C);
392
393   MovieClip *clip = ED_space_clip_get_clip(sc);
394   MovieTracking *tracking = &clip->tracking;
395   MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
396   BoxSelectuserData userdata;
397   rctf rect;
398
399   if (act_track == NULL) {
400     return OPERATOR_CANCELLED;
401   }
402
403   /* get rectangle from operator */
404   WM_operator_properties_border_to_rctf(op, &rect);
405   UI_view2d_region_to_view_rctf(&ar->v2d, &rect, &userdata.rect);
406
407   userdata.changed = false;
408   userdata.select = !RNA_boolean_get(op->ptr, "deselect");
409   userdata.extend = RNA_boolean_get(op->ptr, "extend");
410
411   clip_graph_tracking_values_iterate_track(sc, act_track, &userdata, box_select_cb, NULL, NULL);
412
413   if (userdata.changed) {
414     WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
415
416     return OPERATOR_FINISHED;
417   }
418
419   return OPERATOR_CANCELLED;
420 }
421
422 void CLIP_OT_graph_select_box(wmOperatorType *ot)
423 {
424   /* identifiers */
425   ot->name = "Box Select";
426   ot->description = "Select curve points using box selection";
427   ot->idname = "CLIP_OT_graph_select_box";
428
429   /* api callbacks */
430   ot->invoke = WM_gesture_box_invoke;
431   ot->exec = box_select_graph_exec;
432   ot->modal = WM_gesture_box_modal;
433   ot->poll = clip_graph_knots_poll;
434
435   /* flags */
436   ot->flag = OPTYPE_UNDO;
437
438   /* properties */
439   WM_operator_properties_gesture_box_select(ot);
440 }
441
442 /********************** select all operator *********************/
443
444 static int graph_select_all_markers_exec(bContext *C, wmOperator *op)
445 {
446   SpaceClip *sc = CTX_wm_space_clip(C);
447   MovieClip *clip = ED_space_clip_get_clip(sc);
448   MovieTracking *tracking = &clip->tracking;
449   MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
450   MovieTrackingMarker *marker;
451   int action = RNA_enum_get(op->ptr, "action");
452   int a;
453
454   if (!act_track) {
455     return OPERATOR_CANCELLED;
456   }
457
458   if (action == SEL_TOGGLE) {
459     action = SEL_SELECT;
460
461     for (a = 0; a < act_track->markersnr; a++) {
462       marker = &act_track->markers[a];
463
464       if (marker->flag & MARKER_GRAPH_SEL) {
465         action = SEL_DESELECT;
466         break;
467       }
468     }
469   }
470
471   for (a = 0; a < act_track->markersnr; a++) {
472     marker = &act_track->markers[a];
473
474     switch (action) {
475       case SEL_SELECT:
476         marker->flag |= MARKER_GRAPH_SEL;
477         break;
478       case SEL_DESELECT:
479         marker->flag &= ~MARKER_GRAPH_SEL;
480         break;
481       case SEL_INVERT:
482         marker->flag ^= MARKER_GRAPH_SEL;
483         break;
484     }
485   }
486
487   WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
488
489   return OPERATOR_FINISHED;
490 }
491
492 void CLIP_OT_graph_select_all_markers(wmOperatorType *ot)
493 {
494   /* identifiers */
495   ot->name = "(De)select All Markers";
496   ot->description = "Change selection of all markers of active track";
497   ot->idname = "CLIP_OT_graph_select_all_markers";
498
499   /* api callbacks */
500   ot->exec = graph_select_all_markers_exec;
501   ot->poll = clip_graph_knots_poll;
502
503   /* flags */
504   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
505
506   WM_operator_properties_select_all(ot);
507 }
508
509 /******************** delete curve operator ********************/
510
511 static int delete_curve_exec(bContext *C, wmOperator *UNUSED(op))
512 {
513   SpaceClip *sc = CTX_wm_space_clip(C);
514   MovieClip *clip = ED_space_clip_get_clip(sc);
515   MovieTracking *tracking = &clip->tracking;
516   MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
517
518   if (!act_track) {
519     return OPERATOR_CANCELLED;
520   }
521
522   clip_delete_track(C, clip, act_track);
523
524   return OPERATOR_FINISHED;
525 }
526
527 void CLIP_OT_graph_delete_curve(wmOperatorType *ot)
528 {
529   /* identifiers */
530   ot->name = "Delete Curve";
531   ot->description = "Delete track corresponding to the selected curve";
532   ot->idname = "CLIP_OT_graph_delete_curve";
533
534   /* api callbacks */
535   ot->invoke = WM_operator_confirm;
536   ot->exec = delete_curve_exec;
537   ot->poll = clip_graph_knots_poll;
538
539   /* flags */
540   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
541 }
542
543 /******************** delete knot operator ********************/
544
545 static int delete_knot_exec(bContext *C, wmOperator *UNUSED(op))
546 {
547   SpaceClip *sc = CTX_wm_space_clip(C);
548   MovieClip *clip = ED_space_clip_get_clip(sc);
549   MovieTracking *tracking = &clip->tracking;
550   MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
551
552   if (act_track) {
553     int a = 0;
554
555     while (a < act_track->markersnr) {
556       MovieTrackingMarker *marker = &act_track->markers[a];
557
558       if (marker->flag & MARKER_GRAPH_SEL) {
559         clip_delete_marker(C, clip, act_track, marker);
560       }
561       else {
562         a++;
563       }
564     }
565   }
566
567   return OPERATOR_FINISHED;
568 }
569
570 void CLIP_OT_graph_delete_knot(wmOperatorType *ot)
571 {
572   /* identifiers */
573   ot->name = "Delete Knot";
574   ot->description = "Delete curve knots";
575   ot->idname = "CLIP_OT_graph_delete_knot";
576
577   /* api callbacks */
578   ot->exec = delete_knot_exec;
579   ot->poll = clip_graph_knots_poll;
580
581   /* flags */
582   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
583 }
584
585 /******************** view all operator ********************/
586
587 typedef struct {
588   float min, max;
589 } ViewAllUserData;
590
591 static void view_all_cb(void *userdata,
592                         MovieTrackingTrack *UNUSED(track),
593                         MovieTrackingMarker *UNUSED(marker),
594                         int UNUSED(coord),
595                         int UNUSED(scene_framenr),
596                         float val)
597 {
598   ViewAllUserData *data = (ViewAllUserData *)userdata;
599
600   if (val < data->min) {
601     data->min = val;
602   }
603
604   if (val > data->max) {
605     data->max = val;
606   }
607 }
608
609 static int view_all_exec(bContext *C, wmOperator *UNUSED(op))
610 {
611   Scene *scene = CTX_data_scene(C);
612   ARegion *ar = CTX_wm_region(C);
613   SpaceClip *sc = CTX_wm_space_clip(C);
614   View2D *v2d = &ar->v2d;
615   ViewAllUserData userdata;
616   float extra;
617
618   userdata.max = -FLT_MAX;
619   userdata.min = FLT_MAX;
620
621   clip_graph_tracking_values_iterate(sc,
622                                      (sc->flag & SC_SHOW_GRAPH_SEL_ONLY) != 0,
623                                      (sc->flag & SC_SHOW_GRAPH_HIDDEN) != 0,
624                                      &userdata,
625                                      view_all_cb,
626                                      NULL,
627                                      NULL);
628
629   /* set extents of view to start/end frames */
630   v2d->cur.xmin = (float)SFRA;
631   v2d->cur.xmax = (float)EFRA;
632
633   if (userdata.min < userdata.max) {
634     v2d->cur.ymin = userdata.min;
635     v2d->cur.ymax = userdata.max;
636   }
637   else {
638     v2d->cur.ymin = -10;
639     v2d->cur.ymax = 10;
640   }
641
642   /* we need an extra "buffer" factor on either side so that the endpoints are visible */
643   extra = 0.01f * BLI_rctf_size_x(&v2d->cur);
644   v2d->cur.xmin -= extra;
645   v2d->cur.xmax += extra;
646
647   extra = 0.01f * BLI_rctf_size_y(&v2d->cur);
648   v2d->cur.ymin -= extra;
649   v2d->cur.ymax += extra;
650
651   ED_region_tag_redraw(ar);
652
653   return OPERATOR_FINISHED;
654 }
655
656 void CLIP_OT_graph_view_all(wmOperatorType *ot)
657 {
658   /* identifiers */
659   ot->name = "View All";
660   ot->description = "View all curves in editor";
661   ot->idname = "CLIP_OT_graph_view_all";
662
663   /* api callbacks */
664   ot->exec = view_all_exec;
665   ot->poll = ED_space_clip_graph_poll;
666 }
667
668 /******************** jump to current frame operator ********************/
669
670 void ED_clip_graph_center_current_frame(Scene *scene, ARegion *ar)
671 {
672   View2D *v2d = &ar->v2d;
673   float extra = BLI_rctf_size_x(&v2d->cur) / 2.0f;
674
675   /* set extents of view to start/end frames */
676   v2d->cur.xmin = (float)CFRA - extra;
677   v2d->cur.xmax = (float)CFRA + extra;
678 }
679
680 static int center_current_frame_exec(bContext *C, wmOperator *UNUSED(op))
681 {
682   Scene *scene = CTX_data_scene(C);
683   ARegion *ar = CTX_wm_region(C);
684
685   ED_clip_graph_center_current_frame(scene, ar);
686
687   ED_region_tag_redraw(ar);
688
689   return OPERATOR_FINISHED;
690 }
691
692 void CLIP_OT_graph_center_current_frame(wmOperatorType *ot)
693 {
694   /* identifiers */
695   ot->name = "Center Current Frame";
696   ot->description = "Scroll view so current frame would be centered";
697   ot->idname = "CLIP_OT_graph_center_current_frame";
698
699   /* api callbacks */
700   ot->exec = center_current_frame_exec;
701   ot->poll = ED_space_clip_graph_poll;
702 }
703
704 /********************** disable markers operator *********************/
705
706 static int graph_disable_markers_exec(bContext *C, wmOperator *op)
707 {
708   SpaceClip *sc = CTX_wm_space_clip(C);
709   MovieClip *clip = ED_space_clip_get_clip(sc);
710   MovieTracking *tracking = &clip->tracking;
711   MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
712   MovieTrackingMarker *marker;
713   int action = RNA_enum_get(op->ptr, "action");
714   int a;
715
716   if (!act_track || (act_track->flag & TRACK_LOCKED)) {
717     return OPERATOR_CANCELLED;
718   }
719
720   for (a = 0; a < act_track->markersnr; a++) {
721     marker = &act_track->markers[a];
722
723     if (marker->flag & MARKER_GRAPH_SEL) {
724       if (action == 0) {
725         marker->flag |= MARKER_DISABLED;
726       }
727       else if (action == 1) {
728         marker->flag &= ~MARKER_DISABLED;
729       }
730       else {
731         marker->flag ^= MARKER_DISABLED;
732       }
733     }
734   }
735
736   DEG_id_tag_update(&clip->id, 0);
737
738   WM_event_add_notifier(C, NC_MOVIECLIP | NA_EVALUATED, clip);
739
740   return OPERATOR_FINISHED;
741 }
742
743 void CLIP_OT_graph_disable_markers(wmOperatorType *ot)
744 {
745   static const EnumPropertyItem actions_items[] = {
746       {0, "DISABLE", 0, "Disable", "Disable selected markers"},
747       {1, "ENABLE", 0, "Enable", "Enable selected markers"},
748       {2, "TOGGLE", 0, "Toggle", "Toggle disabled flag for selected markers"},
749       {0, NULL, 0, NULL, NULL},
750   };
751
752   /* identifiers */
753   ot->name = "Disable Markers";
754   ot->description = "Disable/enable selected markers";
755   ot->idname = "CLIP_OT_graph_disable_markers";
756
757   /* api callbacks */
758   ot->exec = graph_disable_markers_exec;
759   ot->poll = ED_space_clip_graph_poll;
760
761   /* flags */
762   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
763
764   /* properties */
765   RNA_def_enum(ot->srna, "action", actions_items, 0, "Action", "Disable action to execute");
766 }