f40514e7574f41239bce70cc90dec2407abbbe9a
[blender.git] / source / blender / editors / space_sequencer / sequencer_select.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) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup spseq
22  */
23
24 #include <stdlib.h>
25 #include <math.h>
26 #include <string.h>
27
28 #include "BLI_blenlib.h"
29 #include "BLI_utildefines.h"
30
31 #include "DNA_scene_types.h"
32
33 #include "BKE_context.h"
34 #include "BKE_report.h"
35 #include "BKE_sequencer.h"
36
37 #include "WM_api.h"
38 #include "WM_types.h"
39
40 #include "RNA_define.h"
41
42 /* for menu/popup icons etc etc*/
43
44 #include "ED_screen.h"
45 #include "ED_sequencer.h"
46 #include "ED_select_utils.h"
47
48 #include "UI_view2d.h"
49
50 /* own include */
51 #include "sequencer_intern.h"
52 static void *find_nearest_marker(int UNUSED(d1), int UNUSED(d2))
53 {
54   return NULL;
55 }
56
57 static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRING BACK */
58 {
59   Sequence *neighbor;
60
61   neighbor = find_neighboring_sequence(scene, test, SEQ_SIDE_LEFT, -1);
62   if (neighbor) {
63     /* Only select neighbor handle if matching handle from test seq is also selected,
64      * or if neighbor was not selected at all up till now.
65      * Otherwise, we get odd mismatch when shift-alt-rmb selecting neighbor strips... */
66     if (!(neighbor->flag & SELECT) || (test->flag & SEQ_LEFTSEL)) {
67       neighbor->flag |= SEQ_RIGHTSEL;
68     }
69     neighbor->flag |= SELECT;
70     recurs_sel_seq(neighbor);
71   }
72   neighbor = find_neighboring_sequence(scene, test, SEQ_SIDE_RIGHT, -1);
73   if (neighbor) {
74     if (!(neighbor->flag & SELECT) || (test->flag & SEQ_RIGHTSEL)) { /* See comment above. */
75       neighbor->flag |= SEQ_LEFTSEL;
76     }
77     neighbor->flag |= SELECT;
78     recurs_sel_seq(neighbor);
79   }
80 }
81
82 /* used for mouse selection and for SEQUENCER_OT_select_active_side() */
83 static void select_active_side(ListBase *seqbase, int sel_side, int channel, int frame)
84 {
85   Sequence *seq;
86
87   for (seq = seqbase->first; seq; seq = seq->next) {
88     if (channel == seq->machine) {
89       switch (sel_side) {
90         case SEQ_SIDE_LEFT:
91           if (frame > (seq->startdisp)) {
92             seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
93             seq->flag |= SELECT;
94           }
95           break;
96         case SEQ_SIDE_RIGHT:
97           if (frame < (seq->startdisp)) {
98             seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
99             seq->flag |= SELECT;
100           }
101           break;
102         case SEQ_SIDE_BOTH:
103           seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
104           seq->flag |= SELECT;
105           break;
106       }
107     }
108   }
109 }
110
111 /* used for mouse selection and for SEQUENCER_OT_select_active_side() */
112 static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
113 {
114   Sequence *seq;
115
116   for (seq = seqbase->first; seq; seq = seq->next) {
117     if (seq_link->machine != seq->machine) {
118       int left_match = (seq->startdisp == seq_link->startdisp) ? 1 : 0;
119       int right_match = (seq->enddisp == seq_link->enddisp) ? 1 : 0;
120
121       if (left_match && right_match) {
122         /* a direct match, copy the selection settinhs */
123         seq->flag &= ~(SELECT | SEQ_LEFTSEL | SEQ_RIGHTSEL);
124         seq->flag |= seq_link->flag & (SELECT | SEQ_LEFTSEL | SEQ_RIGHTSEL);
125
126         recurs_sel_seq(seq);
127       }
128       else if (seq_link->flag & SELECT && (left_match || right_match)) {
129
130         /* clear for reselection */
131         seq->flag &= ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
132
133         if (left_match && seq_link->flag & SEQ_LEFTSEL) {
134           seq->flag |= SELECT | SEQ_LEFTSEL;
135         }
136
137         if (right_match && seq_link->flag & SEQ_RIGHTSEL) {
138           seq->flag |= SELECT | SEQ_RIGHTSEL;
139         }
140
141         recurs_sel_seq(seq);
142       }
143     }
144   }
145 }
146
147 #if 0  // BRING BACK
148 void select_surround_from_last(Scene *scene)
149 {
150   Sequence *seq = get_last_seq(scene);
151
152   if (seq == NULL)
153     return;
154
155   select_surrounding_handles(scene, seq);
156 }
157 #endif
158
159 void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool deselect_all)
160 {
161   Editing *ed = BKE_sequencer_editing_get(scene, false);
162
163   if (deselect_all) {
164     ED_sequencer_deselect_all(scene);
165   }
166
167   BKE_sequencer_active_set(scene, seq);
168
169   if ((seq->type == SEQ_TYPE_IMAGE) || (seq->type == SEQ_TYPE_MOVIE)) {
170     if (seq->strip) {
171       BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
172     }
173   }
174   else if (seq->type == SEQ_TYPE_SOUND_RAM) {
175     if (seq->strip) {
176       BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
177     }
178   }
179   seq->flag |= SELECT;
180   recurs_sel_seq(seq);
181 }
182
183 #if 0
184 static void select_neighbor_from_last(Scene *scene, int lr)
185 {
186   Sequence *seq = BKE_sequencer_active_get(scene);
187   Sequence *neighbor;
188   bool changed = false;
189   if (seq) {
190     neighbor = find_neighboring_sequence(scene, seq, lr, -1);
191     if (neighbor) {
192       switch (lr) {
193         case SEQ_SIDE_LEFT:
194           neighbor->flag |= SELECT;
195           recurs_sel_seq(neighbor);
196           neighbor->flag |= SEQ_RIGHTSEL;
197           seq->flag |= SEQ_LEFTSEL;
198           break;
199         case SEQ_SIDE_RIGHT:
200           neighbor->flag |= SELECT;
201           recurs_sel_seq(neighbor);
202           neighbor->flag |= SEQ_LEFTSEL;
203           seq->flag |= SEQ_RIGHTSEL;
204           break;
205       }
206       seq->flag |= SELECT;
207       changed = true;
208     }
209   }
210   if (changed) {
211     /* pass */
212   }
213 }
214 #endif
215
216 /* (de)select operator */
217 static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
218 {
219   int action = RNA_enum_get(op->ptr, "action");
220
221   Scene *scene = CTX_data_scene(C);
222   Editing *ed = BKE_sequencer_editing_get(scene, false);
223   Sequence *seq;
224
225   if (action == SEL_TOGGLE) {
226     action = SEL_SELECT;
227     for (seq = ed->seqbasep->first; seq; seq = seq->next) {
228       if (seq->flag & SEQ_ALLSEL) {
229         action = SEL_DESELECT;
230         break;
231       }
232     }
233   }
234
235   for (seq = ed->seqbasep->first; seq; seq = seq->next) {
236     switch (action) {
237       case SEL_SELECT:
238         seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
239         seq->flag |= SELECT;
240         break;
241       case SEL_DESELECT:
242         seq->flag &= ~SEQ_ALLSEL;
243         break;
244       case SEL_INVERT:
245         if (seq->flag & SEQ_ALLSEL) {
246           seq->flag &= ~SEQ_ALLSEL;
247         }
248         else {
249           seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
250           seq->flag |= SELECT;
251         }
252         break;
253     }
254   }
255
256   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
257
258   return OPERATOR_FINISHED;
259 }
260
261 void SEQUENCER_OT_select_all(struct wmOperatorType *ot)
262 {
263   /* identifiers */
264   ot->name = "(De)select All";
265   ot->idname = "SEQUENCER_OT_select_all";
266   ot->description = "Select or deselect all strips";
267
268   /* api callbacks */
269   ot->exec = sequencer_de_select_all_exec;
270   ot->poll = sequencer_edit_poll;
271
272   /* flags */
273   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
274
275   WM_operator_properties_select_all(ot);
276 }
277
278 /* (de)select operator */
279 static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
280 {
281   Scene *scene = CTX_data_scene(C);
282   Editing *ed = BKE_sequencer_editing_get(scene, false);
283   Sequence *seq;
284
285   for (seq = ed->seqbasep->first; seq; seq = seq->next) {
286     if (seq->flag & SELECT) {
287       seq->flag &= ~SEQ_ALLSEL;
288     }
289     else {
290       seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
291       seq->flag |= SELECT;
292     }
293   }
294
295   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
296
297   return OPERATOR_FINISHED;
298 }
299
300 void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
301 {
302   /* identifiers */
303   ot->name = "Select Inverse";
304   ot->idname = "SEQUENCER_OT_select_inverse";
305   ot->description = "Select unselected strips";
306
307   /* api callbacks */
308   ot->exec = sequencer_select_inverse_exec;
309   ot->poll = sequencer_edit_poll;
310
311   /* flags */
312   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
313 }
314
315 static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
316 {
317   View2D *v2d = UI_view2d_fromcontext(C);
318   Scene *scene = CTX_data_scene(C);
319   Editing *ed = BKE_sequencer_editing_get(scene, false);
320   const bool extend = RNA_boolean_get(op->ptr, "extend");
321   const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
322   const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle");
323   const bool linked_time = RNA_boolean_get(op->ptr, "linked_time");
324   int left_right = RNA_enum_get(op->ptr, "left_right");
325
326   Sequence *seq, *neighbor, *act_orig;
327   int hand, sel_side;
328   TimeMarker *marker;
329
330   if (ed == NULL) {
331     return OPERATOR_CANCELLED;
332   }
333
334   marker = find_nearest_marker(SCE_MARKERS, 1);  // XXX - dummy function for now
335
336   seq = find_nearest_seq(scene, v2d, &hand, event->mval);
337
338   // XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip
339   if (seq && linked_time && (left_right == SEQ_SELECT_LR_MOUSE)) {
340     left_right = SEQ_SELECT_LR_NONE;
341   }
342
343   if (marker) {
344     int oldflag;
345     /* select timeline marker */
346     if (extend) {
347       oldflag = marker->flag;
348       if (oldflag & SELECT) {
349         marker->flag &= ~SELECT;
350       }
351       else {
352         marker->flag |= SELECT;
353       }
354     }
355     else {
356       /* XXX, in 2.4x, seq selection used to deselect all, need to re-thnik this for 2.5 */
357       /* deselect_markers(0, 0); */
358       marker->flag |= SELECT;
359     }
360   }
361   else if (left_right != SEQ_SELECT_LR_NONE) {
362     /* use different logic for this */
363     float x;
364     ED_sequencer_deselect_all(scene);
365
366     switch (left_right) {
367       case SEQ_SELECT_LR_MOUSE:
368         x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
369         break;
370       case SEQ_SELECT_LR_LEFT:
371         x = CFRA - 1.0f;
372         break;
373       case SEQ_SELECT_LR_RIGHT:
374       default:
375         x = CFRA;
376         break;
377     }
378
379     SEQP_BEGIN (ed, seq) {
380       if (((x < CFRA) && (seq->enddisp <= CFRA)) || ((x >= CFRA) && (seq->startdisp >= CFRA))) {
381         seq->flag |= SELECT;
382         recurs_sel_seq(seq);
383       }
384     }
385     SEQ_END;
386
387     {
388       SpaceSeq *sseq = CTX_wm_space_seq(C);
389       if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
390         TimeMarker *tmarker;
391
392         for (tmarker = scene->markers.first; tmarker; tmarker = tmarker->next) {
393           if (((x < CFRA) && (tmarker->frame <= CFRA)) ||
394               ((x >= CFRA) && (tmarker->frame >= CFRA))) {
395             tmarker->flag |= SELECT;
396           }
397           else {
398             tmarker->flag &= ~SELECT;
399           }
400         }
401       }
402     }
403   }
404   else {
405     act_orig = ed->act_seq;
406
407     if (seq) {
408       if (!extend && !linked_handle) {
409         ED_sequencer_deselect_all(scene);
410       }
411
412       BKE_sequencer_active_set(scene, seq);
413
414       if ((seq->type == SEQ_TYPE_IMAGE) || (seq->type == SEQ_TYPE_MOVIE)) {
415         if (seq->strip) {
416           BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
417         }
418       }
419       else if (seq->type == SEQ_TYPE_SOUND_RAM) {
420         if (seq->strip) {
421           BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
422         }
423       }
424
425       /* On Alt selection, select the strip and bordering handles */
426       if (linked_handle) {
427         if (!ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
428           /* First click selects the strip and its adjacent handles (if valid).
429            * Second click selects the strip,
430            * both of its handles and its adjacent handles (if valid). */
431           const bool is_striponly_selected = ((seq->flag & SEQ_ALLSEL) == SELECT);
432
433           if (!extend) {
434             ED_sequencer_deselect_all(scene);
435           }
436           seq->flag &= ~SEQ_ALLSEL;
437           seq->flag |= is_striponly_selected ? SEQ_ALLSEL : SELECT;
438           select_surrounding_handles(scene, seq);
439         }
440         else {
441           /* always select the strip under the cursor */
442           seq->flag |= SELECT;
443
444           /* First click selects adjacent handles on that side.
445            * Second click selects all strips in that direction.
446            * If there are no adjacent strips, it just selects all in that direction.
447            */
448           sel_side = hand;
449           neighbor = find_neighboring_sequence(scene, seq, sel_side, -1);
450           if (neighbor) {
451             switch (sel_side) {
452               case SEQ_SIDE_LEFT:
453                 if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
454                   if (extend == 0) {
455                     ED_sequencer_deselect_all(scene);
456                   }
457                   seq->flag |= SELECT;
458
459                   select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
460                 }
461                 else {
462                   if (extend == 0) {
463                     ED_sequencer_deselect_all(scene);
464                   }
465                   seq->flag |= SELECT;
466
467                   neighbor->flag |= SELECT;
468                   recurs_sel_seq(neighbor);
469                   neighbor->flag |= SEQ_RIGHTSEL;
470                   seq->flag |= SEQ_LEFTSEL;
471                 }
472                 break;
473               case SEQ_SIDE_RIGHT:
474                 if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
475                   if (extend == 0) {
476                     ED_sequencer_deselect_all(scene);
477                   }
478                   seq->flag |= SELECT;
479
480                   select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
481                 }
482                 else {
483                   if (extend == 0) {
484                     ED_sequencer_deselect_all(scene);
485                   }
486                   seq->flag |= SELECT;
487
488                   neighbor->flag |= SELECT;
489                   recurs_sel_seq(neighbor);
490                   neighbor->flag |= SEQ_LEFTSEL;
491                   seq->flag |= SEQ_RIGHTSEL;
492                 }
493                 break;
494             }
495           }
496           else {
497             if (extend == 0) {
498               ED_sequencer_deselect_all(scene);
499             }
500             select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
501           }
502         }
503       }
504       else {
505         if (extend && (seq->flag & SELECT) && ed->act_seq == act_orig) {
506           switch (hand) {
507             case SEQ_SIDE_NONE:
508               if (linked_handle == 0) {
509                 seq->flag &= ~SEQ_ALLSEL;
510               }
511               break;
512             case SEQ_SIDE_LEFT:
513               seq->flag ^= SEQ_LEFTSEL;
514               break;
515             case SEQ_SIDE_RIGHT:
516               seq->flag ^= SEQ_RIGHTSEL;
517               break;
518           }
519         }
520         else {
521           seq->flag |= SELECT;
522           if (hand == SEQ_SIDE_LEFT) {
523             seq->flag |= SEQ_LEFTSEL;
524           }
525           if (hand == SEQ_SIDE_RIGHT) {
526             seq->flag |= SEQ_RIGHTSEL;
527           }
528         }
529       }
530
531       recurs_sel_seq(seq);
532
533       if (linked_time) {
534         select_linked_time(ed->seqbasep, seq);
535       }
536     }
537     else if (deselect_all) {
538       ED_sequencer_deselect_all(scene);
539     }
540   }
541
542   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
543
544   /* allowing tweaks */
545   return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
546 }
547
548 void SEQUENCER_OT_select(wmOperatorType *ot)
549 {
550   static const EnumPropertyItem sequencer_select_left_right_types[] = {
551       {SEQ_SELECT_LR_NONE, "NONE", 0, "None", "Don't do left-right selection"},
552       {SEQ_SELECT_LR_MOUSE, "MOUSE", 0, "Mouse", "Use mouse position for selection"},
553       {SEQ_SELECT_LR_LEFT, "LEFT", 0, "Left", "Select left"},
554       {SEQ_SELECT_LR_RIGHT, "RIGHT", 0, "Right", "Select right"},
555       {0, NULL, 0, NULL, NULL},
556   };
557
558   /* identifiers */
559   ot->name = "Select";
560   ot->idname = "SEQUENCER_OT_select";
561   ot->description = "Select a strip (last selected becomes the \"active strip\")";
562
563   /* api callbacks */
564   ot->invoke = sequencer_select_invoke;
565   ot->poll = ED_operator_sequencer_active;
566
567   /* flags */
568   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
569
570   /* properties */
571   PropertyRNA *prop;
572   RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
573   prop = RNA_def_boolean(ot->srna,
574                          "deselect_all",
575                          false,
576                          "Deselect On Nothing",
577                          "Deselect all when nothing under the cursor");
578   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
579   RNA_def_boolean(
580       ot->srna, "linked_handle", 0, "Linked Handle", "Select handles next to the active strip");
581   /* for animation this is an enum but atm having an enum isn't useful for us */
582   RNA_def_enum(ot->srna,
583                "left_right",
584                sequencer_select_left_right_types,
585                0,
586                "Left/Right",
587                "Select based on the current frame side the cursor is on");
588   RNA_def_boolean(
589       ot->srna, "linked_time", 0, "Linked Time", "Select other strips at the same time");
590 }
591
592 /* run recursively to select linked */
593 static bool select_more_less_seq__internal(Scene *scene, bool sel, const bool linked)
594 {
595   Editing *ed = BKE_sequencer_editing_get(scene, false);
596   Sequence *seq, *neighbor;
597   bool changed = false;
598   int isel;
599
600   if (ed == NULL) {
601     return changed;
602   }
603
604   if (sel) {
605     sel = SELECT;
606     isel = 0;
607   }
608   else {
609     sel = 0;
610     isel = SELECT;
611   }
612
613   if (!linked) {
614     /* if not linked we only want to touch each seq once, newseq */
615     for (seq = ed->seqbasep->first; seq; seq = seq->next) {
616       seq->tmp = NULL;
617     }
618   }
619
620   for (seq = ed->seqbasep->first; seq; seq = seq->next) {
621     if ((seq->flag & SELECT) == sel) {
622       if (linked || (seq->tmp == NULL)) {
623         /* only get unselected neighbors */
624         neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_LEFT, isel);
625         if (neighbor) {
626           if (sel) {
627             neighbor->flag |= SELECT;
628             recurs_sel_seq(neighbor);
629           }
630           else {
631             neighbor->flag &= ~SELECT;
632           }
633           if (!linked) {
634             neighbor->tmp = (Sequence *)1;
635           }
636           changed = true;
637         }
638         neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_RIGHT, isel);
639         if (neighbor) {
640           if (sel) {
641             neighbor->flag |= SELECT;
642             recurs_sel_seq(neighbor);
643           }
644           else {
645             neighbor->flag &= ~SELECT;
646           }
647           if (!linked) {
648             neighbor->tmp = (Sequence *)1;
649           }
650           changed = true;
651         }
652       }
653     }
654   }
655
656   return changed;
657 }
658
659 /* select more operator */
660 static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
661 {
662   Scene *scene = CTX_data_scene(C);
663
664   if (!select_more_less_seq__internal(scene, true, false)) {
665     return OPERATOR_CANCELLED;
666   }
667
668   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
669
670   return OPERATOR_FINISHED;
671 }
672
673 void SEQUENCER_OT_select_more(wmOperatorType *ot)
674 {
675   /* identifiers */
676   ot->name = "Select More";
677   ot->idname = "SEQUENCER_OT_select_more";
678   ot->description = "Select more strips adjacent to the current selection";
679
680   /* api callbacks */
681   ot->exec = sequencer_select_more_exec;
682   ot->poll = sequencer_edit_poll;
683
684   /* flags */
685   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
686
687   /* properties */
688 }
689
690 /* select less operator */
691 static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
692 {
693   Scene *scene = CTX_data_scene(C);
694
695   if (!select_more_less_seq__internal(scene, false, false)) {
696     return OPERATOR_CANCELLED;
697   }
698
699   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
700
701   return OPERATOR_FINISHED;
702 }
703
704 void SEQUENCER_OT_select_less(wmOperatorType *ot)
705 {
706   /* identifiers */
707   ot->name = "Select Less";
708   ot->idname = "SEQUENCER_OT_select_less";
709   ot->description = "Shrink the current selection of adjacent selected strips";
710
711   /* api callbacks */
712   ot->exec = sequencer_select_less_exec;
713   ot->poll = sequencer_edit_poll;
714
715   /* flags */
716   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
717
718   /* properties */
719 }
720
721 /* select pick linked operator (uses the mouse) */
722 static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
723 {
724   Scene *scene = CTX_data_scene(C);
725   View2D *v2d = UI_view2d_fromcontext(C);
726
727   bool extend = RNA_boolean_get(op->ptr, "extend");
728
729   Sequence *mouse_seq;
730   int selected, hand;
731
732   /* this works like UV, not mesh */
733   mouse_seq = find_nearest_seq(scene, v2d, &hand, event->mval);
734   if (!mouse_seq) {
735     return OPERATOR_FINISHED; /* user error as with mesh?? */
736   }
737
738   if (extend == 0) {
739     ED_sequencer_deselect_all(scene);
740   }
741
742   mouse_seq->flag |= SELECT;
743   recurs_sel_seq(mouse_seq);
744
745   selected = 1;
746   while (selected) {
747     selected = select_more_less_seq__internal(scene, 1, 1);
748   }
749
750   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
751
752   return OPERATOR_FINISHED;
753 }
754
755 void SEQUENCER_OT_select_linked_pick(wmOperatorType *ot)
756 {
757   /* identifiers */
758   ot->name = "Select Pick Linked";
759   ot->idname = "SEQUENCER_OT_select_linked_pick";
760   ot->description = "Select a chain of linked strips nearest to the mouse pointer";
761
762   /* api callbacks */
763   ot->invoke = sequencer_select_linked_pick_invoke;
764   ot->poll = ED_operator_sequencer_active;
765
766   /* flags */
767   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
768
769   /* properties */
770   RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
771 }
772
773 /* select linked operator */
774 static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
775 {
776   Scene *scene = CTX_data_scene(C);
777   bool selected;
778
779   selected = true;
780   while (selected) {
781     selected = select_more_less_seq__internal(scene, true, true);
782   }
783
784   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
785
786   return OPERATOR_FINISHED;
787 }
788
789 void SEQUENCER_OT_select_linked(wmOperatorType *ot)
790 {
791   /* identifiers */
792   ot->name = "Select Linked";
793   ot->idname = "SEQUENCER_OT_select_linked";
794   ot->description = "Select all strips adjacent to the current selection";
795
796   /* api callbacks */
797   ot->exec = sequencer_select_linked_exec;
798   ot->poll = sequencer_edit_poll;
799
800   /* flags */
801   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
802
803   /* properties */
804 }
805
806 /* select handles operator */
807 static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
808 {
809   Scene *scene = CTX_data_scene(C);
810   Editing *ed = BKE_sequencer_editing_get(scene, false);
811   Sequence *seq;
812   int sel_side = RNA_enum_get(op->ptr, "side");
813
814   for (seq = ed->seqbasep->first; seq; seq = seq->next) {
815     if (seq->flag & SELECT) {
816       switch (sel_side) {
817         case SEQ_SIDE_LEFT:
818           seq->flag &= ~SEQ_RIGHTSEL;
819           seq->flag |= SEQ_LEFTSEL;
820           break;
821         case SEQ_SIDE_RIGHT:
822           seq->flag &= ~SEQ_LEFTSEL;
823           seq->flag |= SEQ_RIGHTSEL;
824           break;
825         case SEQ_SIDE_BOTH:
826           seq->flag |= SEQ_LEFTSEL | SEQ_RIGHTSEL;
827           break;
828       }
829     }
830   }
831
832   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
833
834   return OPERATOR_FINISHED;
835 }
836
837 void SEQUENCER_OT_select_handles(wmOperatorType *ot)
838 {
839   /* identifiers */
840   ot->name = "Select Handles";
841   ot->idname = "SEQUENCER_OT_select_handles";
842   ot->description = "Select gizmo handles on the sides of the selected strip";
843
844   /* api callbacks */
845   ot->exec = sequencer_select_handles_exec;
846   ot->poll = sequencer_edit_poll;
847
848   /* flags */
849   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
850
851   /* properties */
852   RNA_def_enum(ot->srna,
853                "side",
854                prop_side_types,
855                SEQ_SIDE_BOTH,
856                "Side",
857                "The side of the handle that is selected");
858 }
859
860 /* select side operator */
861 static int sequencer_select_active_side_exec(bContext *C, wmOperator *op)
862 {
863   Scene *scene = CTX_data_scene(C);
864   Editing *ed = BKE_sequencer_editing_get(scene, false);
865   Sequence *seq_act = BKE_sequencer_active_get(scene);
866
867   if (ed == NULL || seq_act == NULL) {
868     return OPERATOR_CANCELLED;
869   }
870
871   seq_act->flag |= SELECT;
872
873   select_active_side(
874       ed->seqbasep, RNA_enum_get(op->ptr, "side"), seq_act->machine, seq_act->startdisp);
875
876   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
877
878   return OPERATOR_FINISHED;
879 }
880
881 void SEQUENCER_OT_select_active_side(wmOperatorType *ot)
882 {
883   /* identifiers */
884   ot->name = "Select Active Side";
885   ot->idname = "SEQUENCER_OT_select_active_side";
886   ot->description = "Select strips on the nominated side of the active strip";
887
888   /* api callbacks */
889   ot->exec = sequencer_select_active_side_exec;
890   ot->poll = sequencer_edit_poll;
891
892   /* flags */
893   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
894
895   /* properties */
896   RNA_def_enum(ot->srna,
897                "side",
898                prop_side_types,
899                SEQ_SIDE_BOTH,
900                "Side",
901                "The side of the handle that is selected");
902 }
903
904 /* box_select operator */
905 static int sequencer_box_select_exec(bContext *C, wmOperator *op)
906 {
907   Scene *scene = CTX_data_scene(C);
908   Editing *ed = BKE_sequencer_editing_get(scene, false);
909   if (ed == NULL) {
910     return OPERATOR_CANCELLED;
911   }
912
913   View2D *v2d = UI_view2d_fromcontext(C);
914
915   const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
916   const bool select = (sel_op != SEL_OP_SUB);
917   if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
918     ED_sequencer_deselect_all(scene);
919   }
920
921   rctf rectf;
922   WM_operator_properties_border_to_rctf(op, &rectf);
923   UI_view2d_region_to_view_rctf(v2d, &rectf, &rectf);
924
925   for (Sequence *seq = ed->seqbasep->first; seq; seq = seq->next) {
926     rctf rq;
927     seq_rectf(seq, &rq);
928     if (BLI_rctf_isect(&rq, &rectf, NULL)) {
929       SET_FLAG_FROM_TEST(seq->flag, select, SELECT);
930       recurs_sel_seq(seq);
931     }
932   }
933
934   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
935
936   return OPERATOR_FINISHED;
937 }
938
939 /* ****** Box Select ****** */
940 void SEQUENCER_OT_select_box(wmOperatorType *ot)
941 {
942   /* identifiers */
943   ot->name = "Box Select";
944   ot->idname = "SEQUENCER_OT_select_box";
945   ot->description = "Select strips using box selection";
946
947   /* api callbacks */
948   ot->invoke = WM_gesture_box_invoke;
949   ot->exec = sequencer_box_select_exec;
950   ot->modal = WM_gesture_box_modal;
951   ot->cancel = WM_gesture_box_cancel;
952
953   ot->poll = ED_operator_sequencer_active;
954
955   /* flags */
956   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
957
958   /* properties */
959   WM_operator_properties_gesture_box(ot);
960   WM_operator_properties_select_operation_simple(ot);
961 }
962
963 /* ****** Selected Grouped ****** */
964
965 enum {
966   SEQ_SELECT_GROUP_TYPE,
967   SEQ_SELECT_GROUP_TYPE_BASIC,
968   SEQ_SELECT_GROUP_TYPE_EFFECT,
969   SEQ_SELECT_GROUP_DATA,
970   SEQ_SELECT_GROUP_EFFECT,
971   SEQ_SELECT_GROUP_EFFECT_LINK,
972   SEQ_SELECT_GROUP_OVERLAP,
973 };
974
975 static const EnumPropertyItem sequencer_prop_select_grouped_types[] = {
976     {SEQ_SELECT_GROUP_TYPE, "TYPE", 0, "Type", "Shared strip type"},
977     {SEQ_SELECT_GROUP_TYPE_BASIC,
978      "TYPE_BASIC",
979      0,
980      "Global Type",
981      "All strips of same basic type (Graphical or Sound)"},
982     {SEQ_SELECT_GROUP_TYPE_EFFECT,
983      "TYPE_EFFECT",
984      0,
985      "Effect Type",
986      "Shared strip effect type (if active strip is not an effect one, select all non-effect "
987      "strips)"},
988     {SEQ_SELECT_GROUP_DATA, "DATA", 0, "Data", "Shared data (scene, image, sound, etc.)"},
989     {SEQ_SELECT_GROUP_EFFECT, "EFFECT", 0, "Effect", "Shared effects"},
990     {SEQ_SELECT_GROUP_EFFECT_LINK,
991      "EFFECT_LINK",
992      0,
993      "Effect/Linked",
994      "Other strips affected by the active one (sharing some time, and below or effect-assigned)"},
995     {SEQ_SELECT_GROUP_OVERLAP, "OVERLAP", 0, "Overlap", "Overlapping time"},
996     {0, NULL, 0, NULL, NULL},
997 };
998
999 #define SEQ_IS_SOUND(_seq) ((_seq->type & SEQ_TYPE_SOUND_RAM) && !(_seq->type & SEQ_TYPE_EFFECT))
1000
1001 #define SEQ_IS_EFFECT(_seq) ((_seq->type & SEQ_TYPE_EFFECT) != 0)
1002
1003 #define SEQ_USE_DATA(_seq) \
1004   (ELEM(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq))
1005
1006 #define SEQ_CHANNEL_CHECK(_seq, _chan) (ELEM((_chan), 0, (_seq)->machine))
1007
1008 static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel)
1009 {
1010   Sequence *seq;
1011   bool changed = false;
1012
1013   SEQP_BEGIN (ed, seq) {
1014     if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == actseq->type) {
1015       seq->flag |= SELECT;
1016       changed = true;
1017     }
1018   }
1019   SEQ_END;
1020
1021   return changed;
1022 }
1023
1024 static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int channel)
1025 {
1026   Sequence *seq;
1027   bool changed = false;
1028   const bool is_sound = SEQ_IS_SOUND(actseq);
1029
1030   SEQP_BEGIN (ed, seq) {
1031     if (SEQ_CHANNEL_CHECK(seq, channel) && (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq))) {
1032       seq->flag |= SELECT;
1033       changed = true;
1034     }
1035   }
1036   SEQ_END;
1037
1038   return changed;
1039 }
1040
1041 static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int channel)
1042 {
1043   Sequence *seq;
1044   bool changed = false;
1045   const bool is_effect = SEQ_IS_EFFECT(actseq);
1046
1047   SEQP_BEGIN (ed, seq) {
1048     if (SEQ_CHANNEL_CHECK(seq, channel) &&
1049         (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq))) {
1050       seq->flag |= SELECT;
1051       changed = true;
1052     }
1053   }
1054   SEQ_END;
1055
1056   return changed;
1057 }
1058
1059 static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel)
1060 {
1061   Sequence *seq;
1062   bool changed = false;
1063   const char *dir = actseq->strip ? actseq->strip->dir : NULL;
1064
1065   if (!SEQ_USE_DATA(actseq)) {
1066     return changed;
1067   }
1068
1069   if (SEQ_HAS_PATH(actseq) && dir) {
1070     SEQP_BEGIN (ed, seq) {
1071       if (SEQ_CHANNEL_CHECK(seq, channel) && SEQ_HAS_PATH(seq) && seq->strip &&
1072           STREQ(seq->strip->dir, dir)) {
1073         seq->flag |= SELECT;
1074         changed = true;
1075       }
1076     }
1077     SEQ_END;
1078   }
1079   else if (actseq->type == SEQ_TYPE_SCENE) {
1080     Scene *sce = actseq->scene;
1081     SEQP_BEGIN (ed, seq) {
1082       if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_SCENE && seq->scene == sce) {
1083         seq->flag |= SELECT;
1084         changed = true;
1085       }
1086     }
1087     SEQ_END;
1088   }
1089   else if (actseq->type == SEQ_TYPE_MOVIECLIP) {
1090     MovieClip *clip = actseq->clip;
1091     SEQP_BEGIN (ed, seq) {
1092       if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MOVIECLIP &&
1093           seq->clip == clip) {
1094         seq->flag |= SELECT;
1095         changed = true;
1096       }
1097     }
1098     SEQ_END;
1099   }
1100   else if (actseq->type == SEQ_TYPE_MASK) {
1101     struct Mask *mask = actseq->mask;
1102     SEQP_BEGIN (ed, seq) {
1103       if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MASK && seq->mask == mask) {
1104         seq->flag |= SELECT;
1105         changed = true;
1106       }
1107     }
1108     SEQ_END;
1109   }
1110
1111   return changed;
1112 }
1113
1114 static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int channel)
1115 {
1116   Sequence *seq;
1117   bool changed = false;
1118   bool effects[SEQ_TYPE_MAX + 1];
1119   int i;
1120
1121   for (i = 0; i <= SEQ_TYPE_MAX; i++) {
1122     effects[i] = false;
1123   }
1124
1125   SEQP_BEGIN (ed, seq) {
1126     if (SEQ_CHANNEL_CHECK(seq, channel) && (seq->type & SEQ_TYPE_EFFECT) &&
1127         ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
1128       effects[seq->type] = true;
1129     }
1130   }
1131   SEQ_END;
1132
1133   SEQP_BEGIN (ed, seq) {
1134     if (SEQ_CHANNEL_CHECK(seq, channel) && effects[seq->type]) {
1135       if (seq->seq1) {
1136         seq->seq1->flag |= SELECT;
1137       }
1138       if (seq->seq2) {
1139         seq->seq2->flag |= SELECT;
1140       }
1141       if (seq->seq3) {
1142         seq->seq3->flag |= SELECT;
1143       }
1144       changed = true;
1145     }
1146   }
1147   SEQ_END;
1148
1149   return changed;
1150 }
1151
1152 static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq)
1153 {
1154   Sequence *seq;
1155   bool changed = false;
1156
1157   SEQP_BEGIN (ed, seq) {
1158     if (!((seq->startdisp >= actseq->enddisp) || (seq->enddisp < actseq->startdisp))) {
1159       seq->flag |= SELECT;
1160       changed = true;
1161     }
1162   }
1163   SEQ_END;
1164
1165   return changed;
1166 }
1167
1168 static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int channel)
1169 {
1170   Sequence *seq = NULL;
1171   bool changed = false;
1172   const bool is_audio = ((actseq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(actseq));
1173   int startdisp = actseq->startdisp;
1174   int enddisp = actseq->enddisp;
1175   int machine = actseq->machine;
1176   SeqIterator iter;
1177
1178   SEQP_BEGIN (ed, seq) {
1179     seq->tmp = NULL;
1180   }
1181   SEQ_END;
1182
1183   actseq->tmp = POINTER_FROM_INT(true);
1184
1185   for (BKE_sequence_iterator_begin(ed, &iter, true); iter.valid;
1186        BKE_sequence_iterator_next(&iter)) {
1187     seq = iter.seq;
1188
1189     /* Ignore all seqs already selected! */
1190     /* Ignore all seqs not sharing some time with active one. */
1191     /* Ignore all seqs of incompatible types (audio vs video). */
1192     if (!SEQ_CHANNEL_CHECK(seq, channel) || (seq->flag & SELECT) || (seq->startdisp >= enddisp) ||
1193         (seq->enddisp < startdisp) || (!is_audio && SEQ_IS_SOUND(seq)) ||
1194         (is_audio && !((seq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(seq)))) {
1195       continue;
1196     }
1197
1198     /* If the seq is an effect one, we need extra checking! */
1199     if (SEQ_IS_EFFECT(seq) && ((seq->seq1 && seq->seq1->tmp) || (seq->seq2 && seq->seq2->tmp) ||
1200                                (seq->seq3 && seq->seq3->tmp))) {
1201       if (startdisp > seq->startdisp) {
1202         startdisp = seq->startdisp;
1203       }
1204       if (enddisp < seq->enddisp) {
1205         enddisp = seq->enddisp;
1206       }
1207       if (machine < seq->machine) {
1208         machine = seq->machine;
1209       }
1210
1211       seq->tmp = POINTER_FROM_INT(true);
1212
1213       seq->flag |= SELECT;
1214       changed = true;
1215
1216       /* Unfortunately, we must restart checks from the beginning. */
1217       BKE_sequence_iterator_end(&iter);
1218       BKE_sequence_iterator_begin(ed, &iter, true);
1219     }
1220
1221     /* Video strips below active one, or any strip for audio (order do no matters here!). */
1222     else if (seq->machine < machine || is_audio) {
1223       seq->flag |= SELECT;
1224       changed = true;
1225     }
1226   }
1227   BKE_sequence_iterator_end(&iter);
1228
1229   return changed;
1230 }
1231
1232 #undef SEQ_IS_SOUND
1233 #undef SEQ_IS_EFFECT
1234 #undef SEQ_USE_DATA
1235
1236 static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
1237 {
1238   Scene *scene = CTX_data_scene(C);
1239   Editing *ed = BKE_sequencer_editing_get(scene, false);
1240   Sequence *seq, *actseq = BKE_sequencer_active_get(scene);
1241
1242   const int type = RNA_enum_get(op->ptr, "type");
1243   const int channel = RNA_boolean_get(op->ptr, "use_active_channel") ? actseq->machine : 0;
1244   const bool extend = RNA_boolean_get(op->ptr, "extend");
1245
1246   bool changed = false;
1247
1248   if (actseq == NULL) {
1249     BKE_report(op->reports, RPT_ERROR, "No active sequence!");
1250     return OPERATOR_CANCELLED;
1251   }
1252
1253   if (!extend) {
1254     SEQP_BEGIN (ed, seq) {
1255       seq->flag &= ~SELECT;
1256       changed = true;
1257     }
1258     SEQ_END;
1259   }
1260
1261   switch (type) {
1262     case SEQ_SELECT_GROUP_TYPE:
1263       changed |= select_grouped_type(ed, actseq, channel);
1264       break;
1265     case SEQ_SELECT_GROUP_TYPE_BASIC:
1266       changed |= select_grouped_type_basic(ed, actseq, channel);
1267       break;
1268     case SEQ_SELECT_GROUP_TYPE_EFFECT:
1269       changed |= select_grouped_type_effect(ed, actseq, channel);
1270       break;
1271     case SEQ_SELECT_GROUP_DATA:
1272       changed |= select_grouped_data(ed, actseq, channel);
1273       break;
1274     case SEQ_SELECT_GROUP_EFFECT:
1275       changed |= select_grouped_effect(ed, actseq, channel);
1276       break;
1277     case SEQ_SELECT_GROUP_EFFECT_LINK:
1278       changed |= select_grouped_effect_link(ed, actseq, channel);
1279       break;
1280     case SEQ_SELECT_GROUP_OVERLAP:
1281       changed |= select_grouped_time_overlap(ed, actseq);
1282       break;
1283     default:
1284       BLI_assert(0);
1285       break;
1286   }
1287
1288   if (changed) {
1289     WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
1290     return OPERATOR_FINISHED;
1291   }
1292
1293   return OPERATOR_CANCELLED;
1294 }
1295
1296 void SEQUENCER_OT_select_grouped(wmOperatorType *ot)
1297 {
1298   /* identifiers */
1299   ot->name = "Select Grouped";
1300   ot->description = "Select all strips grouped by various properties";
1301   ot->idname = "SEQUENCER_OT_select_grouped";
1302
1303   /* api callbacks */
1304   ot->invoke = WM_menu_invoke;
1305   ot->exec = sequencer_select_grouped_exec;
1306   ot->poll = sequencer_edit_poll;
1307
1308   /* flags */
1309   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1310
1311   /* properties */
1312   ot->prop = RNA_def_enum(ot->srna, "type", sequencer_prop_select_grouped_types, 0, "Type", "");
1313   RNA_def_boolean(ot->srna,
1314                   "extend",
1315                   false,
1316                   "Extend",
1317                   "Extend selection instead of deselecting everything first");
1318   RNA_def_boolean(ot->srna,
1319                   "use_active_channel",
1320                   false,
1321                   "Same Channel",
1322                   "Only consider strips on the same channel as the active one");
1323 }