26a596ead07ef64bde122284cc2b1a8cfdf8c62a
[blender.git] / source / blender / editors / space_clip / tracking_select.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 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/tracking_select.c
29  *  \ingroup spclip
30  */
31
32 #include "MEM_guardedalloc.h"
33
34 #include "DNA_camera_types.h"
35 #include "DNA_constraint_types.h"
36 #include "DNA_gpencil_types.h"
37 #include "DNA_movieclip_types.h"
38 #include "DNA_object_types.h"   /* SELECT */
39 #include "DNA_scene_types.h"
40
41 #include "BLI_utildefines.h"
42 #include "BLI_math.h"
43 #include "BLI_listbase.h"
44 #include "BLI_rect.h"
45 #include "BLI_lasso.h"
46 #include "BLI_blenlib.h"
47
48 #include "BKE_main.h"
49 #include "BKE_context.h"
50 #include "BKE_constraint.h"
51 #include "BKE_movieclip.h"
52 #include "BKE_tracking.h"
53 #include "BKE_global.h"
54 #include "BKE_depsgraph.h"
55 #include "BKE_object.h"
56 #include "BKE_report.h"
57 #include "BKE_scene.h"
58 #include "BKE_library.h"
59 #include "BKE_sound.h"
60
61 #include "WM_api.h"
62 #include "WM_types.h"
63
64 #include "ED_screen.h"
65 #include "ED_clip.h"
66 #include "ED_keyframing.h"
67
68 #include "IMB_imbuf_types.h"
69 #include "IMB_imbuf.h"
70
71 #include "UI_interface.h"
72
73 #include "RNA_access.h"
74 #include "RNA_define.h"
75
76 #include "PIL_time.h"
77
78 #include "UI_view2d.h"
79
80 #include "clip_intern.h"    // own include
81
82 static float dist_to_crns(float co[2], float pos[2], float crns[4][2]);
83
84 /********************** mouse select operator *********************/
85
86 static int mouse_on_side(float co[2], float x1, float y1, float x2, float y2, float epsx, float epsy)
87 {
88         if (x1 > x2)
89
90                 SWAP(float, x1, x2);
91
92         if (y1 > y2)
93                 SWAP(float, y1, y2);
94
95         return (co[0] >= x1 - epsx && co[0] <= x2 + epsx) && (co[1] >= y1 - epsy && co[1] <= y2 + epsy);
96 }
97
98 static int mouse_on_rect(float co[2], float pos[2], float min[2], float max[2], float epsx, float epsy)
99 {
100         return mouse_on_side(co, pos[0] + min[0], pos[1] + min[1], pos[0] + max[0], pos[1] + min[1], epsx, epsy) ||
101                mouse_on_side(co, pos[0] + min[0], pos[1] + min[1], pos[0] + min[0], pos[1] + max[1], epsx, epsy) ||
102                mouse_on_side(co, pos[0] + min[0], pos[1] + max[1], pos[0] + max[0], pos[1] + max[1], epsx, epsy) ||
103                mouse_on_side(co, pos[0] + max[0], pos[1] + min[1], pos[0] + max[0], pos[1] + max[1], epsx, epsy);
104 }
105
106 static int mouse_on_crns(float co[2], float pos[2], float crns[4][2], float epsx, float epsy)
107 {
108         float dist = dist_to_crns(co, pos, crns);
109
110         return dist < MAX2(epsx, epsy);
111 }
112
113 static int track_mouse_area(const bContext *C, float co[2], MovieTrackingTrack *track)
114 {
115         SpaceClip *sc = CTX_wm_space_clip(C);
116         int framenr = ED_space_clip_get_clip_frame_number(sc);
117         MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
118         float pat_min[2], pat_max[2];
119         float epsx, epsy;
120         int width, height;
121
122         ED_space_clip_get_size(sc, &width, &height);
123
124         BKE_tracking_marker_pattern_minmax(marker, pat_min, pat_max);
125
126         epsx = MIN4(pat_min[0] - marker->search_min[0], marker->search_max[0] - pat_max[0],
127                     fabsf(pat_min[0]), fabsf(pat_max[0])) / 2;
128         epsy = MIN4(pat_min[1] - marker->search_min[1], marker->search_max[1] - pat_max[1],
129                     fabsf(pat_min[1]), fabsf(pat_max[1])) / 2;
130
131         epsx = MAX2(epsx, 2.0f / width);
132         epsy = MAX2(epsy, 2.0f / height);
133
134         if (sc->flag & SC_SHOW_MARKER_SEARCH) {
135                 if (mouse_on_rect(co, marker->pos, marker->search_min, marker->search_max, epsx, epsy))
136                         return TRACK_AREA_SEARCH;
137         }
138
139         if ((marker->flag & MARKER_DISABLED) == 0) {
140                 if (sc->flag & SC_SHOW_MARKER_PATTERN)
141                         if (mouse_on_crns(co, marker->pos, marker->pattern_corners, epsx, epsy))
142                                 return TRACK_AREA_PAT;
143
144                 epsx = 12.0f / width;
145                 epsy = 12.0f / height;
146
147                 if (fabsf(co[0] - marker->pos[0] - track->offset[0]) < epsx &&
148                     fabsf(co[1] - marker->pos[1] - track->offset[1]) <= epsy)
149                 {
150                         return TRACK_AREA_POINT;
151                 }
152         }
153
154         return TRACK_AREA_NONE;
155 }
156
157 static float dist_to_rect(float co[2], float pos[2], float min[2], float max[2])
158 {
159         float d1, d2, d3, d4;
160         float p[2] = {co[0] - pos[0], co[1] - pos[1]};
161         float v1[2] = {min[0], min[1]}, v2[2] = {max[0], min[1]};
162         float v3[2] = {max[0], max[1]}, v4[2] = {min[0], max[1]};
163
164         d1 = dist_to_line_segment_v2(p, v1, v2);
165         d2 = dist_to_line_segment_v2(p, v2, v3);
166         d3 = dist_to_line_segment_v2(p, v3, v4);
167         d4 = dist_to_line_segment_v2(p, v4, v1);
168
169         return MIN4(d1, d2, d3, d4);
170 }
171
172 static float dist_to_crns(float co[2], float pos[2], float crns[4][2])
173 {
174         float d1, d2, d3, d4;
175         float p[2] = {co[0] - pos[0], co[1] - pos[1]};
176         float *v1 = crns[0], *v2 = crns[1];
177         float *v3 = crns[2], *v4 = crns[3];
178
179         d1 = dist_to_line_segment_v2(p, v1, v2);
180         d2 = dist_to_line_segment_v2(p, v2, v3);
181         d3 = dist_to_line_segment_v2(p, v3, v4);
182         d4 = dist_to_line_segment_v2(p, v4, v1);
183
184         return MIN4(d1, d2, d3, d4);
185 }
186
187 static MovieTrackingTrack *find_nearest_track(SpaceClip *sc, ListBase *tracksbase, float co[2])
188 {
189         MovieTrackingTrack *track = NULL, *cur;
190         float mindist = 0.0f;
191         int framenr = ED_space_clip_get_clip_frame_number(sc);
192
193         cur = tracksbase->first;
194         while (cur) {
195                 MovieTrackingMarker *marker = BKE_tracking_marker_get(cur, framenr);
196
197                 if (((cur->flag & TRACK_HIDDEN) == 0) && MARKER_VISIBLE(sc, cur, marker)) {
198                         float dist, d1, d2 = FLT_MAX, d3 = FLT_MAX;
199
200                         /* distance to marker point */
201                         d1 = sqrtf((co[0] - marker->pos[0] - cur->offset[0]) * (co[0] - marker->pos[0] - cur->offset[0]) +
202                                    (co[1] - marker->pos[1] - cur->offset[1]) * (co[1] - marker->pos[1] - cur->offset[1]));
203
204                         /* distance to pattern boundbox */
205                         if (sc->flag & SC_SHOW_MARKER_PATTERN)
206                                 d2 = dist_to_crns(co, marker->pos, marker->pattern_corners);
207
208                         /* distance to search boundbox */
209                         if (sc->flag & SC_SHOW_MARKER_SEARCH && TRACK_VIEW_SELECTED(sc, cur))
210                                 d3 = dist_to_rect(co, marker->pos, marker->search_min, marker->search_max);
211
212                         /* choose minimal distance. useful for cases of overlapped markers. */
213                         dist = MIN3(d1, d2, d3);
214
215                         if (track == NULL || dist < mindist) {
216                                 track = cur;
217                                 mindist = dist;
218                         }
219                 }
220
221                 cur = cur->next;
222         }
223
224         return track;
225 }
226
227 static int mouse_select(bContext *C, float co[2], int 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         ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
233         MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
234         MovieTrackingTrack *track = NULL;   /* selected marker */
235
236         track = find_nearest_track(sc, tracksbase, co);
237
238         if (track) {
239                 int area = track_mouse_area(C, co, track);
240
241                 if (!extend || !TRACK_VIEW_SELECTED(sc, track))
242                         area = TRACK_AREA_ALL;
243
244                 if (extend && TRACK_AREA_SELECTED(track, area)) {
245                         if (track == act_track)
246                                 BKE_tracking_track_deselect(track, area);
247                         else
248                                 clip->tracking.act_track = track;
249                 }
250                 else {
251                         if (area == TRACK_AREA_POINT)
252                                 area = TRACK_AREA_ALL;
253
254                         BKE_tracking_track_select(tracksbase, track, area, extend);
255                         clip->tracking.act_track = track;
256                 }
257         }
258
259         if (!extend) {
260                 sc->xlockof = 0.0f;
261                 sc->ylockof = 0.0f;
262         }
263
264         BKE_tracking_dopesheet_tag_update(tracking);
265
266         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
267
268         return OPERATOR_FINISHED;
269 }
270
271 static int select_exec(bContext *C, wmOperator *op)
272 {
273         float co[2];
274         int extend;
275
276         RNA_float_get_array(op->ptr, "location", co);
277         extend = RNA_boolean_get(op->ptr, "extend");
278
279         return mouse_select(C, co, extend);
280 }
281
282 static int select_invoke(bContext *C, wmOperator *op, wmEvent *event)
283 {
284         SpaceClip *sc = CTX_wm_space_clip(C);
285         ARegion *ar = CTX_wm_region(C);
286
287         float co[2];
288         int extend = RNA_boolean_get(op->ptr, "extend");
289
290         if (!extend) {
291                 MovieTrackingTrack *track = tracking_marker_check_slide(C, event, NULL, NULL, NULL);
292
293                 if (track) {
294                         SpaceClip *sc = CTX_wm_space_clip(C);
295                         MovieClip *clip = ED_space_clip_get_clip(sc);
296
297                         clip->tracking.act_track = track;
298
299                         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
300
301                         return OPERATOR_PASS_THROUGH;
302                 }
303         }
304
305         ED_clip_mouse_pos(sc, ar, event, co);
306         RNA_float_set_array(op->ptr, "location", co);
307
308         return select_exec(C, op);
309 }
310
311 void CLIP_OT_select(wmOperatorType *ot)
312 {
313         /* identifiers */
314         ot->name = "Select";
315         ot->description = "Select tracking markers";
316         ot->idname = "CLIP_OT_select";
317
318         /* api callbacks */
319         ot->exec = select_exec;
320         ot->invoke = select_invoke;
321         //ot->poll = ED_space_clip_tracking_poll; // so mask view can Ctrl+RMB markers
322         ot->poll = ED_space_clip_view_clip_poll;
323
324         /* flags */
325         ot->flag = OPTYPE_UNDO;
326
327         /* properties */
328         RNA_def_boolean(ot->srna, "extend", 0,
329                         "Extend", "Extend selection rather than clearing the existing selection");
330         RNA_def_float_vector(ot->srna, "location", 2, NULL, -FLT_MAX, FLT_MAX,
331                              "Location", "Mouse location in normalized coordinates, 0.0 to 1.0 is within the image bounds", -100.0f, 100.0f);
332 }
333
334 /********************** border select operator *********************/
335
336 static int border_select_exec(bContext *C, wmOperator *op)
337 {
338         SpaceClip *sc = CTX_wm_space_clip(C);
339         ARegion *ar = CTX_wm_region(C);
340
341         MovieClip *clip = ED_space_clip_get_clip(sc);
342         MovieTracking *tracking = &clip->tracking;
343         MovieTrackingTrack *track;
344         ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
345         rcti rect;
346         rctf rectf;
347         int change = FALSE, mode, extend;
348         int framenr = ED_space_clip_get_clip_frame_number(sc);
349
350         /* get rectangle from operator */
351         rect.xmin = RNA_int_get(op->ptr, "xmin");
352         rect.ymin = RNA_int_get(op->ptr, "ymin");
353         rect.xmax = RNA_int_get(op->ptr, "xmax");
354         rect.ymax = RNA_int_get(op->ptr, "ymax");
355
356         ED_clip_point_stable_pos(sc, ar, rect.xmin, rect.ymin, &rectf.xmin, &rectf.ymin);
357         ED_clip_point_stable_pos(sc, ar, rect.xmax, rect.ymax, &rectf.xmax, &rectf.ymax);
358
359         mode = RNA_int_get(op->ptr, "gesture_mode");
360         extend = RNA_boolean_get(op->ptr, "extend");
361
362         /* do actual selection */
363         track = tracksbase->first;
364         while (track) {
365                 if ((track->flag & TRACK_HIDDEN) == 0) {
366                         MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
367
368                         if (MARKER_VISIBLE(sc, track, marker)) {
369                                 if (BLI_in_rctf_v(&rectf, marker->pos)) {
370                                         if (mode == GESTURE_MODAL_SELECT)
371                                                 BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT);
372                                         else
373                                                 BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT);
374                                 }
375                                 else if (!extend) {
376                                         BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT);
377                                 }
378
379                                 change = TRUE;
380                         }
381                 }
382
383                 track = track->next;
384         }
385
386         if (change) {
387                 BKE_tracking_dopesheet_tag_update(tracking);
388
389                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
390
391                 return OPERATOR_FINISHED;
392         }
393
394         return OPERATOR_CANCELLED;
395 }
396
397 void CLIP_OT_select_border(wmOperatorType *ot)
398 {
399         /* identifiers */
400         ot->name = "Border Select";
401         ot->description = "Select markers using border selection";
402         ot->idname = "CLIP_OT_select_border";
403
404         /* api callbacks */
405         ot->invoke = WM_border_select_invoke;
406         ot->exec = border_select_exec;
407         ot->modal = WM_border_select_modal;
408         ot->poll = ED_space_clip_tracking_poll;
409
410         /* flags */
411         ot->flag = OPTYPE_UNDO;
412
413         /* properties */
414         WM_operator_properties_gesture_border(ot, TRUE);
415 }
416
417 /********************** lasso select operator *********************/
418
419 static int do_lasso_select_marker(bContext *C, int mcords[][2], short moves, short select)
420 {
421         SpaceClip *sc = CTX_wm_space_clip(C);
422         ARegion *ar = CTX_wm_region(C);
423
424         MovieClip *clip = ED_space_clip_get_clip(sc);
425         MovieTracking *tracking = &clip->tracking;
426         MovieTrackingTrack *track;
427         ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
428         rcti rect;
429         int change = FALSE;
430         int framenr = ED_space_clip_get_clip_frame_number(sc);
431
432         /* get rectangle from operator */
433         BLI_lasso_boundbox(&rect, mcords, moves);
434
435         /* do actual selection */
436         track = tracksbase->first;
437         while (track) {
438                 if ((track->flag & TRACK_HIDDEN) == 0) {
439                         MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
440
441                         if (MARKER_VISIBLE(sc, track, marker)) {
442                                 float screen_co[2];
443
444                                 /* marker in screen coords */
445                                 ED_clip_point_stable_pos__reverse(sc, ar, marker->pos, screen_co);
446
447                                 if (BLI_in_rcti(&rect, screen_co[0], screen_co[1]) &&
448                                     BLI_lasso_is_point_inside(mcords, moves, screen_co[0], screen_co[1], V2D_IS_CLIPPED))
449                                 {
450                                         if (select)
451                                                 BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT);
452                                         else
453                                                 BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT);
454                                 }
455
456                                 change = TRUE;
457                         }
458                 }
459
460                 track = track->next;
461         }
462
463         if (change) {
464                 BKE_tracking_dopesheet_tag_update(tracking);
465
466                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
467         }
468
469         return change;
470 }
471
472 static int clip_lasso_select_exec(bContext *C, wmOperator *op)
473 {
474         int mcords_tot;
475         int (*mcords)[2] = WM_gesture_lasso_path_to_array(C, op, &mcords_tot);
476
477         if (mcords) {
478                 short select;
479
480                 select = !RNA_boolean_get(op->ptr, "deselect");
481                 do_lasso_select_marker(C, mcords, mcords_tot, select);
482
483                 MEM_freeN(mcords);
484
485                 return OPERATOR_FINISHED;
486         }
487         return OPERATOR_PASS_THROUGH;
488 }
489
490 void CLIP_OT_select_lasso(wmOperatorType *ot)
491 {
492         /* identifiers */
493         ot->name = "Lasso Select";
494         ot->description = "Select markers using lasso selection";
495         ot->idname = "CLIP_OT_select_lasso";
496
497         /* api callbacks */
498         ot->invoke = WM_gesture_lasso_invoke;
499         ot->modal = WM_gesture_lasso_modal;
500         ot->exec = clip_lasso_select_exec;
501         ot->poll = ED_space_clip_tracking_poll;
502         ot->cancel = WM_gesture_lasso_cancel;
503
504         /* flags */
505         ot->flag = OPTYPE_UNDO;
506
507         /* properties */
508         RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", "");
509         RNA_def_boolean(ot->srna, "deselect", 0, "Deselect", "Deselect rather than select items");
510         RNA_def_boolean(ot->srna, "extend", 1, "Extend", "Extend selection instead of deselecting everything first");
511 }
512
513 /********************** circle select operator *********************/
514
515 static int marker_inside_ellipse(MovieTrackingMarker *marker, float offset[2], float ellipse[2])
516 {
517         /* normalized ellipse: ell[0] = scaleX, ell[1] = scaleY */
518         float x, y;
519
520         x = (marker->pos[0] - offset[0]) * ellipse[0];
521         y = (marker->pos[1] - offset[1]) * ellipse[1];
522
523         return x * x + y * y < 1.0f;
524 }
525
526 static int circle_select_exec(bContext *C, wmOperator *op)
527 {
528         SpaceClip *sc = CTX_wm_space_clip(C);
529         ARegion *ar = CTX_wm_region(C);
530
531         MovieClip *clip = ED_space_clip_get_clip(sc);
532         MovieTracking *tracking = &clip->tracking;
533         MovieTrackingTrack *track;
534         ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
535         int x, y, radius, width, height, mode, change = FALSE;
536         float zoomx, zoomy, offset[2], ellipse[2];
537         int framenr = ED_space_clip_get_clip_frame_number(sc);
538
539         /* get operator properties */
540         x = RNA_int_get(op->ptr, "x");
541         y = RNA_int_get(op->ptr, "y");
542         radius = RNA_int_get(op->ptr, "radius");
543
544         mode = RNA_int_get(op->ptr, "gesture_mode");
545
546         /* compute ellipse and position in unified coordinates */
547         ED_space_clip_get_size(sc, &width, &height);
548         ED_space_clip_get_zoom(sc, ar, &zoomx, &zoomy);
549
550         ellipse[0] = width * zoomx / radius;
551         ellipse[1] = height * zoomy / radius;
552
553         ED_clip_point_stable_pos(sc, ar, x, y, &offset[0], &offset[1]);
554
555         /* do selection */
556         track = tracksbase->first;
557         while (track) {
558                 if ((track->flag & TRACK_HIDDEN) == 0) {
559                         MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr);
560
561                         if (MARKER_VISIBLE(sc, track, marker) && marker_inside_ellipse(marker, offset, ellipse)) {
562                                 if (mode == GESTURE_MODAL_SELECT)
563                                         BKE_tracking_track_flag_set(track, TRACK_AREA_ALL, SELECT);
564                                 else
565                                         BKE_tracking_track_flag_clear(track, TRACK_AREA_ALL, SELECT);
566
567                                 change = TRUE;
568                         }
569                 }
570
571                 track = track->next;
572         }
573
574         if (change) {
575                 BKE_tracking_dopesheet_tag_update(tracking);
576
577                 WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
578
579                 return OPERATOR_FINISHED;
580         }
581
582         return OPERATOR_CANCELLED;
583 }
584
585 void CLIP_OT_select_circle(wmOperatorType *ot)
586 {
587         /* identifiers */
588         ot->name = "Circle Select";
589         ot->description = "Select markers using circle selection";
590         ot->idname = "CLIP_OT_select_circle";
591
592         /* api callbacks */
593         ot->invoke = WM_gesture_circle_invoke;
594         ot->modal = WM_gesture_circle_modal;
595         ot->exec = circle_select_exec;
596         ot->poll = ED_space_clip_tracking_poll;
597
598         /* flags */
599         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
600
601         /* properties */
602         RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX);
603         RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX);
604         RNA_def_int(ot->srna, "radius", 0, INT_MIN, INT_MAX, "Radius", "", INT_MIN, INT_MAX);
605         RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Gesture Mode", "", INT_MIN, INT_MAX);
606 }
607
608 /********************** select all operator *********************/
609
610 static int select_all_exec(bContext *C, wmOperator *op)
611 {
612         SpaceClip *sc = CTX_wm_space_clip(C);
613         MovieClip *clip = ED_space_clip_get_clip(sc);
614         MovieTracking *tracking = &clip->tracking;
615         MovieTrackingTrack *track = NULL;   /* selected track */
616         MovieTrackingMarker *marker;
617         ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
618         int action = RNA_enum_get(op->ptr, "action");
619         int framenr = ED_space_clip_get_clip_frame_number(sc);
620         int has_selection = FALSE;
621
622         if (action == SEL_TOGGLE) {
623                 action = SEL_SELECT;
624                 track = tracksbase->first;
625                 while (track) {
626                         if (TRACK_VIEW_SELECTED(sc, track)) {
627                                 marker = BKE_tracking_marker_get(track, framenr);
628
629                                 if (MARKER_VISIBLE(sc, track, marker)) {
630                                         action = SEL_DESELECT;
631                                         break;
632                                 }
633                         }
634
635                         track = track->next;
636                 }
637         }
638
639         track = tracksbase->first;
640         while (track) {
641                 if ((track->flag & TRACK_HIDDEN) == 0) {
642                         marker = BKE_tracking_marker_get(track, framenr);
643
644                         if (MARKER_VISIBLE(sc, track, marker)) {
645                                 switch (action) {
646                                         case SEL_SELECT:
647                                                 track->flag |= SELECT;
648                                                 track->pat_flag |= SELECT;
649                                                 track->search_flag |= SELECT;
650                                                 break;
651                                         case SEL_DESELECT:
652                                                 track->flag &= ~SELECT;
653                                                 track->pat_flag &= ~SELECT;
654                                                 track->search_flag &= ~SELECT;
655                                                 break;
656                                         case SEL_INVERT:
657                                                 track->flag ^= SELECT;
658                                                 track->pat_flag ^= SELECT;
659                                                 track->search_flag ^= SELECT;
660                                                 break;
661                                 }
662                         }
663                 }
664
665                 if (TRACK_VIEW_SELECTED(sc, track))
666                         has_selection = TRUE;
667
668                 track = track->next;
669         }
670
671         if (!has_selection)
672                 sc->flag &= ~SC_LOCK_SELECTION;
673
674         BKE_tracking_dopesheet_tag_update(tracking);
675
676         WM_event_add_notifier(C, NC_GEOM | ND_SELECT, NULL);
677
678         return OPERATOR_FINISHED;
679 }
680
681 void CLIP_OT_select_all(wmOperatorType *ot)
682 {
683         /* identifiers */
684         ot->name = "(De)select All";
685         ot->description = "Change selection of all tracking markers";
686         ot->idname = "CLIP_OT_select_all";
687
688         /* api callbacks */
689         ot->exec = select_all_exec;
690         ot->poll = ED_space_clip_tracking_poll;
691
692         /* flags */
693         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
694
695         WM_operator_properties_select_all(ot);
696 }
697
698 /********************** select grouped operator *********************/
699
700 static int select_groped_exec(bContext *C, wmOperator *op)
701 {
702         SpaceClip *sc = CTX_wm_space_clip(C);
703         MovieClip *clip = ED_space_clip_get_clip(sc);
704         MovieTrackingTrack *track;
705         MovieTrackingMarker *marker;
706         MovieTracking *tracking = &clip->tracking;
707         ListBase *tracksbase = BKE_tracking_get_active_tracks(tracking);
708         int group = RNA_enum_get(op->ptr, "group");
709         int framenr = ED_space_clip_get_clip_frame_number(sc);
710
711         track = tracksbase->first;
712         while (track) {
713                 int ok = FALSE;
714
715                 marker = BKE_tracking_marker_get(track, framenr);
716
717                 if (group == 0) { /* Keyframed */
718                         ok = marker->framenr == framenr && (marker->flag & MARKER_TRACKED) == 0;
719                 }
720                 else if (group == 1) { /* Estimated */
721                         ok = marker->framenr != framenr;
722                 }
723                 else if (group == 2) { /* tracked */
724                         ok = marker->framenr == framenr && (marker->flag & MARKER_TRACKED);
725                 }
726                 else if (group == 3) { /* locked */
727                         ok = track->flag & TRACK_LOCKED;
728                 }
729                 else if (group == 4) { /* disabled */
730                         ok = marker->flag & MARKER_DISABLED;
731                 }
732                 else if (group == 5) { /* color */
733                         MovieTrackingTrack *act_track = BKE_tracking_track_get_active(tracking);
734
735                         if (act_track) {
736                                 ok = (track->flag & TRACK_CUSTOMCOLOR) == (act_track->flag & TRACK_CUSTOMCOLOR);
737
738                                 if (ok && track->flag & TRACK_CUSTOMCOLOR)
739                                         ok = equals_v3v3(track->color, act_track->color);
740                         }
741                 }
742                 else if (group == 6) { /* failed */
743                         ok = (track->flag & TRACK_HAS_BUNDLE) == 0;
744                 }
745
746                 if (ok) {
747                         track->flag |= SELECT;
748                         if (sc->flag & SC_SHOW_MARKER_PATTERN)
749                                 track->pat_flag |= SELECT;
750                         if (sc->flag & SC_SHOW_MARKER_SEARCH)
751                                 track->search_flag |= SELECT;
752                 }
753
754                 track = track->next;
755         }
756
757         BKE_tracking_dopesheet_tag_update(tracking);
758
759         WM_event_add_notifier(C, NC_MOVIECLIP | ND_DISPLAY, clip);
760
761         return OPERATOR_FINISHED;
762 }
763
764 void CLIP_OT_select_grouped(wmOperatorType *ot)
765 {
766         static EnumPropertyItem select_group_items[] = {
767                 {0, "KEYFRAMED", 0, "Keyframed tracks", "Select all keyframed tracks"},
768                 {1, "ESTIMATED", 0, "Estimated tracks", "Select all estimated tracks"},
769                 {2, "TRACKED", 0, "Tracked tracks", "Select all tracked tracks"},
770                 {3, "LOCKED", 0, "Locked tracks", "Select all locked tracks"},
771                 {4, "DISABLED", 0, "Disabled tracks", "Select all disabled tracks"},
772                 {5, "COLOR", 0, "Tracks with same color", "Select all tracks with same color as active track"},
773                 {6, "FAILED", 0, "Failed Tracks", "Select all tracks which failed to be reconstructed"},
774                 {0, NULL, 0, NULL, NULL}
775         };
776
777         /* identifiers */
778         ot->name = "Select Grouped";
779         ot->description = "Select all tracks from specified group";
780         ot->idname = "CLIP_OT_select_grouped";
781
782         /* api callbacks */
783         ot->exec = select_groped_exec;
784         ot->poll = ED_space_clip_tracking_poll;
785
786         /* flags */
787         ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
788
789         /* proeprties */
790         RNA_def_enum(ot->srna, "group", select_group_items, TRACK_CLEAR_REMAINED, "Action", "Clear action to execute");
791 }