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