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