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