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 <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "BLI_blenlib.h"
29 #include "BLI_math.h"
30 #include "BLI_utildefines.h"
31 
32 #include "DNA_scene_types.h"
33 
34 #include "BKE_context.h"
35 #include "BKE_report.h"
36 #include "BKE_sequencer.h"
37 
38 #include "WM_api.h"
39 #include "WM_types.h"
40 
41 #include "RNA_define.h"
42 
43 /* For menu, popup, icons, etc. */
44 
45 #include "ED_outliner.h"
46 #include "ED_screen.h"
47 #include "ED_select_utils.h"
48 #include "ED_sequencer.h"
49 
50 #include "UI_view2d.h"
51 
52 /* Own include. */
53 #include "sequencer_intern.h"
54 
55 /* -------------------------------------------------------------------- */
56 /** \name Selection Utilities
57  * \{ */
58 
select_surrounding_handles(Scene * scene,Sequence * test)59 static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRING BACK */
60 {
61   Sequence *neighbor;
62 
63   neighbor = find_neighboring_sequence(scene, test, SEQ_SIDE_LEFT, -1);
64   if (neighbor) {
65     /* Only select neighbor handle if matching handle from test seq is also selected,
66      * or if neighbor was not selected at all up till now.
67      * Otherwise, we get odd mismatch when shift-alt-rmb selecting neighbor strips... */
68     if (!(neighbor->flag & SELECT) || (test->flag & SEQ_LEFTSEL)) {
69       neighbor->flag |= SEQ_RIGHTSEL;
70     }
71     neighbor->flag |= SELECT;
72     recurs_sel_seq(neighbor);
73   }
74   neighbor = find_neighboring_sequence(scene, test, SEQ_SIDE_RIGHT, -1);
75   if (neighbor) {
76     if (!(neighbor->flag & SELECT) || (test->flag & SEQ_RIGHTSEL)) { /* See comment above. */
77       neighbor->flag |= SEQ_LEFTSEL;
78     }
79     neighbor->flag |= SELECT;
80     recurs_sel_seq(neighbor);
81   }
82 }
83 
84 /* Used for mouse selection in SEQUENCER_OT_select. */
select_active_side(ListBase * seqbase,int sel_side,int channel,int frame)85 static void select_active_side(ListBase *seqbase, int sel_side, int channel, int frame)
86 {
87   Sequence *seq;
88 
89   for (seq = seqbase->first; seq; seq = seq->next) {
90     if (channel == seq->machine) {
91       switch (sel_side) {
92         case SEQ_SIDE_LEFT:
93           if (frame > (seq->startdisp)) {
94             seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
95             seq->flag |= SELECT;
96           }
97           break;
98         case SEQ_SIDE_RIGHT:
99           if (frame < (seq->startdisp)) {
100             seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
101             seq->flag |= SELECT;
102           }
103           break;
104         case SEQ_SIDE_BOTH:
105           seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
106           seq->flag |= SELECT;
107           break;
108       }
109     }
110   }
111 }
112 
113 /* Used for mouse selection in SEQUENCER_OT_select_side. */
select_active_side_range(ListBase * seqbase,const int sel_side,const int frame_ranges[MAXSEQ],const int frame_ignore)114 static void select_active_side_range(ListBase *seqbase,
115                                      const int sel_side,
116                                      const int frame_ranges[MAXSEQ],
117                                      const int frame_ignore)
118 {
119   Sequence *seq;
120 
121   for (seq = seqbase->first; seq; seq = seq->next) {
122     if (seq->machine < MAXSEQ) {
123       const int frame = frame_ranges[seq->machine];
124       if (frame == frame_ignore) {
125         continue;
126       }
127       switch (sel_side) {
128         case SEQ_SIDE_LEFT:
129           if (frame > (seq->startdisp)) {
130             seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
131             seq->flag |= SELECT;
132           }
133           break;
134         case SEQ_SIDE_RIGHT:
135           if (frame < (seq->startdisp)) {
136             seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
137             seq->flag |= SELECT;
138           }
139           break;
140         case SEQ_SIDE_BOTH:
141           seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
142           seq->flag |= SELECT;
143           break;
144       }
145     }
146   }
147 }
148 
149 /* Used for mouse selection in SEQUENCER_OT_select */
select_linked_time(ListBase * seqbase,Sequence * seq_link)150 static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
151 {
152   Sequence *seq;
153 
154   for (seq = seqbase->first; seq; seq = seq->next) {
155     if (seq_link->machine != seq->machine) {
156       int left_match = (seq->startdisp == seq_link->startdisp) ? 1 : 0;
157       int right_match = (seq->enddisp == seq_link->enddisp) ? 1 : 0;
158 
159       if (left_match && right_match) {
160         /* Direct match, copy the selection settings. */
161         seq->flag &= ~(SELECT | SEQ_LEFTSEL | SEQ_RIGHTSEL);
162         seq->flag |= seq_link->flag & (SELECT | SEQ_LEFTSEL | SEQ_RIGHTSEL);
163 
164         recurs_sel_seq(seq);
165       }
166       else if (seq_link->flag & SELECT && (left_match || right_match)) {
167 
168         /* Clear for reselection. */
169         seq->flag &= ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
170 
171         if (left_match && seq_link->flag & SEQ_LEFTSEL) {
172           seq->flag |= SELECT | SEQ_LEFTSEL;
173         }
174 
175         if (right_match && seq_link->flag & SEQ_RIGHTSEL) {
176           seq->flag |= SELECT | SEQ_RIGHTSEL;
177         }
178 
179         recurs_sel_seq(seq);
180       }
181     }
182   }
183 }
184 
185 #if 0 /* BRING BACK */
186 void select_surround_from_last(Scene *scene)
187 {
188   Sequence *seq = get_last_seq(scene);
189 
190   if (seq == NULL) {
191     return;
192   }
193 
194   select_surrounding_handles(scene, seq);
195 }
196 #endif
197 
ED_sequencer_select_sequence_single(Scene * scene,Sequence * seq,bool deselect_all)198 void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool deselect_all)
199 {
200   Editing *ed = BKE_sequencer_editing_get(scene, false);
201 
202   if (deselect_all) {
203     ED_sequencer_deselect_all(scene);
204   }
205 
206   BKE_sequencer_active_set(scene, seq);
207 
208   if ((seq->type == SEQ_TYPE_IMAGE) || (seq->type == SEQ_TYPE_MOVIE)) {
209     if (seq->strip) {
210       BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
211     }
212   }
213   else if (seq->type == SEQ_TYPE_SOUND_RAM) {
214     if (seq->strip) {
215       BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
216     }
217   }
218   seq->flag |= SELECT;
219   recurs_sel_seq(seq);
220 }
221 
222 #if 0
223 static void select_neighbor_from_last(Scene *scene, int lr)
224 {
225   Sequence *seq = BKE_sequencer_active_get(scene);
226   Sequence *neighbor;
227   bool changed = false;
228   if (seq) {
229     neighbor = find_neighboring_sequence(scene, seq, lr, -1);
230     if (neighbor) {
231       switch (lr) {
232         case SEQ_SIDE_LEFT:
233           neighbor->flag |= SELECT;
234           recurs_sel_seq(neighbor);
235           neighbor->flag |= SEQ_RIGHTSEL;
236           seq->flag |= SEQ_LEFTSEL;
237           break;
238         case SEQ_SIDE_RIGHT:
239           neighbor->flag |= SELECT;
240           recurs_sel_seq(neighbor);
241           neighbor->flag |= SEQ_LEFTSEL;
242           seq->flag |= SEQ_RIGHTSEL;
243           break;
244       }
245       seq->flag |= SELECT;
246       changed = true;
247     }
248   }
249   if (changed) {
250     /* Pass. */
251   }
252 }
253 #endif
254 
255 /** \} */
256 
257 /* -------------------------------------------------------------------- */
258 /** \name (De)select All Operator
259  * \{ */
260 
sequencer_de_select_all_exec(bContext * C,wmOperator * op)261 static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
262 {
263   int action = RNA_enum_get(op->ptr, "action");
264 
265   Scene *scene = CTX_data_scene(C);
266   Editing *ed = BKE_sequencer_editing_get(scene, false);
267   Sequence *seq;
268 
269   if (action == SEL_TOGGLE) {
270     action = SEL_SELECT;
271     for (seq = ed->seqbasep->first; seq; seq = seq->next) {
272       if (seq->flag & SEQ_ALLSEL) {
273         action = SEL_DESELECT;
274         break;
275       }
276     }
277   }
278 
279   for (seq = ed->seqbasep->first; seq; seq = seq->next) {
280     switch (action) {
281       case SEL_SELECT:
282         seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
283         seq->flag |= SELECT;
284         break;
285       case SEL_DESELECT:
286         seq->flag &= ~SEQ_ALLSEL;
287         break;
288       case SEL_INVERT:
289         if (seq->flag & SEQ_ALLSEL) {
290           seq->flag &= ~SEQ_ALLSEL;
291         }
292         else {
293           seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
294           seq->flag |= SELECT;
295         }
296         break;
297     }
298   }
299 
300   ED_outliner_select_sync_from_sequence_tag(C);
301 
302   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
303 
304   return OPERATOR_FINISHED;
305 }
306 
SEQUENCER_OT_select_all(struct wmOperatorType * ot)307 void SEQUENCER_OT_select_all(struct wmOperatorType *ot)
308 {
309   /* Identifiers. */
310   ot->name = "(De)select All";
311   ot->idname = "SEQUENCER_OT_select_all";
312   ot->description = "Select or deselect all strips";
313 
314   /* Api callbacks. */
315   ot->exec = sequencer_de_select_all_exec;
316   ot->poll = sequencer_edit_poll;
317 
318   /* Flags. */
319   ot->flag = OPTYPE_UNDO;
320 
321   WM_operator_properties_select_all(ot);
322 }
323 
324 /** \} */
325 
326 /* -------------------------------------------------------------------- */
327 /** \name Select Inverse Operator
328  * \{ */
329 
sequencer_select_inverse_exec(bContext * C,wmOperator * UNUSED (op))330 static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
331 {
332   Scene *scene = CTX_data_scene(C);
333   Editing *ed = BKE_sequencer_editing_get(scene, false);
334   Sequence *seq;
335 
336   for (seq = ed->seqbasep->first; seq; seq = seq->next) {
337     if (seq->flag & SELECT) {
338       seq->flag &= ~SEQ_ALLSEL;
339     }
340     else {
341       seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
342       seq->flag |= SELECT;
343     }
344   }
345 
346   ED_outliner_select_sync_from_sequence_tag(C);
347 
348   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
349 
350   return OPERATOR_FINISHED;
351 }
352 
SEQUENCER_OT_select_inverse(struct wmOperatorType * ot)353 void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
354 {
355   /* Identifiers. */
356   ot->name = "Select Inverse";
357   ot->idname = "SEQUENCER_OT_select_inverse";
358   ot->description = "Select unselected strips";
359 
360   /* Api callbacks. */
361   ot->exec = sequencer_select_inverse_exec;
362   ot->poll = sequencer_edit_poll;
363 
364   /* Flags. */
365   ot->flag = OPTYPE_UNDO;
366 }
367 
368 /** \} */
369 
370 /* -------------------------------------------------------------------- */
371 /** \name Select Operator
372  * \{ */
373 
sequencer_select_exec(bContext * C,wmOperator * op)374 static int sequencer_select_exec(bContext *C, wmOperator *op)
375 {
376   View2D *v2d = UI_view2d_fromcontext(C);
377   Scene *scene = CTX_data_scene(C);
378   Editing *ed = BKE_sequencer_editing_get(scene, false);
379   const bool extend = RNA_boolean_get(op->ptr, "extend");
380   const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
381   const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle");
382   const bool linked_time = RNA_boolean_get(op->ptr, "linked_time");
383   bool side_of_frame = RNA_boolean_get(op->ptr, "side_of_frame");
384   bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
385   int mval[2];
386   int ret_value = OPERATOR_CANCELLED;
387 
388   mval[0] = RNA_int_get(op->ptr, "mouse_x");
389   mval[1] = RNA_int_get(op->ptr, "mouse_y");
390 
391   Sequence *seq, *neighbor, *act_orig;
392   int hand, sel_side;
393 
394   if (ed == NULL) {
395     return OPERATOR_CANCELLED;
396   }
397 
398   if (extend) {
399     wait_to_deselect_others = false;
400   }
401 
402   seq = find_nearest_seq(scene, v2d, &hand, mval);
403 
404   /* XXX - not nice, Ctrl+RMB needs to do side_of_frame only when not over a strip */
405   if (seq && linked_time) {
406     side_of_frame = false;
407   }
408 
409   /* Select left, right or overlapping the current frame. */
410   if (side_of_frame) {
411     /* Use different logic for this. */
412     if (extend == false) {
413       ED_sequencer_deselect_all(scene);
414     }
415 
416     const float x = UI_view2d_region_to_view_x(v2d, mval[0]);
417 
418     SEQ_CURRENT_BEGIN (ed, seq) {
419       if (((x < CFRA) && (seq->enddisp <= CFRA)) || ((x >= CFRA) && (seq->startdisp >= CFRA))) {
420         /* Select left or right. */
421         seq->flag |= SELECT;
422         recurs_sel_seq(seq);
423       }
424     }
425     SEQ_CURRENT_END;
426 
427     {
428       SpaceSeq *sseq = CTX_wm_space_seq(C);
429       if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
430         TimeMarker *tmarker;
431 
432         for (tmarker = scene->markers.first; tmarker; tmarker = tmarker->next) {
433           if (((x < CFRA) && (tmarker->frame <= CFRA)) ||
434               ((x >= CFRA) && (tmarker->frame >= CFRA))) {
435             tmarker->flag |= SELECT;
436           }
437           else {
438             tmarker->flag &= ~SELECT;
439           }
440         }
441       }
442     }
443 
444     ret_value = OPERATOR_FINISHED;
445   }
446   else {
447     act_orig = ed->act_seq;
448 
449     if (seq) {
450       /* Are we trying to select a handle that's already selected? */
451       const bool handle_selected = ((hand == SEQ_SIDE_LEFT) && (seq->flag & SEQ_LEFTSEL)) ||
452                                    ((hand == SEQ_SIDE_RIGHT) && (seq->flag & SEQ_RIGHTSEL));
453 
454       if (wait_to_deselect_others && (seq->flag & SELECT) &&
455           (hand == SEQ_SIDE_NONE || handle_selected)) {
456         ret_value = OPERATOR_RUNNING_MODAL;
457       }
458       else if (!extend && !linked_handle) {
459         ED_sequencer_deselect_all(scene);
460         ret_value = OPERATOR_FINISHED;
461       }
462       else {
463         ret_value = OPERATOR_FINISHED;
464       }
465 
466       BKE_sequencer_active_set(scene, seq);
467 
468       if ((seq->type == SEQ_TYPE_IMAGE) || (seq->type == SEQ_TYPE_MOVIE)) {
469         if (seq->strip) {
470           BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
471         }
472       }
473       else if (seq->type == SEQ_TYPE_SOUND_RAM) {
474         if (seq->strip) {
475           BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
476         }
477       }
478 
479       /* On Alt selection, select the strip and bordering handles. */
480       if (linked_handle) {
481         if (!ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
482           /* First click selects the strip and its adjacent handles (if valid).
483            * Second click selects the strip,
484            * both of its handles and its adjacent handles (if valid). */
485           const bool is_striponly_selected = ((seq->flag & SEQ_ALLSEL) == SELECT);
486 
487           if (!extend) {
488             ED_sequencer_deselect_all(scene);
489           }
490           seq->flag &= ~SEQ_ALLSEL;
491           seq->flag |= is_striponly_selected ? SEQ_ALLSEL : SELECT;
492           select_surrounding_handles(scene, seq);
493         }
494         else {
495           /* Always select the strip under the cursor. */
496           seq->flag |= SELECT;
497 
498           /* First click selects adjacent handles on that side.
499            * Second click selects all strips in that direction.
500            * If there are no adjacent strips, it just selects all in that direction.
501            */
502           sel_side = hand;
503           neighbor = find_neighboring_sequence(scene, seq, sel_side, -1);
504           if (neighbor) {
505             switch (sel_side) {
506               case SEQ_SIDE_LEFT:
507                 if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
508                   if (extend == 0) {
509                     ED_sequencer_deselect_all(scene);
510                   }
511                   seq->flag |= SELECT;
512 
513                   select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
514                 }
515                 else {
516                   if (extend == 0) {
517                     ED_sequencer_deselect_all(scene);
518                   }
519                   seq->flag |= SELECT;
520 
521                   neighbor->flag |= SELECT;
522                   recurs_sel_seq(neighbor);
523                   neighbor->flag |= SEQ_RIGHTSEL;
524                   seq->flag |= SEQ_LEFTSEL;
525                 }
526                 break;
527               case SEQ_SIDE_RIGHT:
528                 if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
529                   if (extend == 0) {
530                     ED_sequencer_deselect_all(scene);
531                   }
532                   seq->flag |= SELECT;
533 
534                   select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
535                 }
536                 else {
537                   if (extend == 0) {
538                     ED_sequencer_deselect_all(scene);
539                   }
540                   seq->flag |= SELECT;
541 
542                   neighbor->flag |= SELECT;
543                   recurs_sel_seq(neighbor);
544                   neighbor->flag |= SEQ_LEFTSEL;
545                   seq->flag |= SEQ_RIGHTSEL;
546                 }
547                 break;
548             }
549           }
550           else {
551             if (extend == 0) {
552               ED_sequencer_deselect_all(scene);
553             }
554             select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
555           }
556         }
557 
558         ret_value = OPERATOR_FINISHED;
559       }
560       else {
561         if (extend && (seq->flag & SELECT) && ed->act_seq == act_orig) {
562           switch (hand) {
563             case SEQ_SIDE_NONE:
564               if (linked_handle == 0) {
565                 seq->flag &= ~SEQ_ALLSEL;
566               }
567               break;
568             case SEQ_SIDE_LEFT:
569               seq->flag ^= SEQ_LEFTSEL;
570               break;
571             case SEQ_SIDE_RIGHT:
572               seq->flag ^= SEQ_RIGHTSEL;
573               break;
574           }
575           ret_value = OPERATOR_FINISHED;
576         }
577         else {
578           seq->flag |= SELECT;
579           if (hand == SEQ_SIDE_LEFT) {
580             seq->flag |= SEQ_LEFTSEL;
581           }
582           if (hand == SEQ_SIDE_RIGHT) {
583             seq->flag |= SEQ_RIGHTSEL;
584           }
585         }
586       }
587 
588       recurs_sel_seq(seq);
589 
590       if (linked_time) {
591         select_linked_time(ed->seqbasep, seq);
592       }
593 
594       BLI_assert((ret_value & OPERATOR_CANCELLED) == 0);
595     }
596     else if (deselect_all) {
597       ED_sequencer_deselect_all(scene);
598       ret_value = OPERATOR_FINISHED;
599     }
600   }
601 
602   ED_outliner_select_sync_from_sequence_tag(C);
603 
604   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
605 
606   return ret_value;
607 }
608 
SEQUENCER_OT_select(wmOperatorType * ot)609 void SEQUENCER_OT_select(wmOperatorType *ot)
610 {
611   PropertyRNA *prop;
612 
613   /* Identifiers. */
614   ot->name = "Select";
615   ot->idname = "SEQUENCER_OT_select";
616   ot->description = "Select a strip (last selected becomes the \"active strip\")";
617 
618   /* Api callbacks. */
619   ot->exec = sequencer_select_exec;
620   ot->invoke = WM_generic_select_invoke;
621   ot->modal = WM_generic_select_modal;
622   ot->poll = ED_operator_sequencer_active;
623 
624   /* Flags. */
625   ot->flag = OPTYPE_UNDO;
626 
627   /* Properties. */
628   WM_operator_properties_generic_select(ot);
629 
630   prop = RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend the selection");
631   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
632 
633   prop = RNA_def_boolean(ot->srna,
634                          "deselect_all",
635                          false,
636                          "Deselect On Nothing",
637                          "Deselect all when nothing under the cursor");
638   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
639 
640   prop = RNA_def_boolean(ot->srna,
641                          "linked_handle",
642                          false,
643                          "Linked Handle",
644                          "Select handles next to the active strip");
645   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
646 
647   prop = RNA_def_boolean(
648       ot->srna, "linked_time", false, "Linked Time", "Select other strips at the same time");
649   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
650 
651   prop = RNA_def_boolean(
652       ot->srna,
653       "side_of_frame",
654       false,
655       "Side of Frame",
656       "Select all strips on same side of the current frame as the mouse cursor");
657   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
658 }
659 
660 /** \} */
661 
662 /* -------------------------------------------------------------------- */
663 /** \name Select More Operator
664  * \{ */
665 
666 /* Run recursively to select linked. */
select_more_less_seq__internal(Scene * scene,bool sel,const bool linked)667 static bool select_more_less_seq__internal(Scene *scene, bool sel, const bool linked)
668 {
669   Editing *ed = BKE_sequencer_editing_get(scene, false);
670   Sequence *seq, *neighbor;
671   bool changed = false;
672   int isel;
673 
674   if (ed == NULL) {
675     return changed;
676   }
677 
678   if (sel) {
679     sel = SELECT;
680     isel = 0;
681   }
682   else {
683     sel = 0;
684     isel = SELECT;
685   }
686 
687   if (!linked) {
688     /* If not linked we only want to touch each seq once, newseq. */
689     for (seq = ed->seqbasep->first; seq; seq = seq->next) {
690       seq->tmp = NULL;
691     }
692   }
693 
694   for (seq = ed->seqbasep->first; seq; seq = seq->next) {
695     if ((seq->flag & SELECT) == sel) {
696       if (linked || (seq->tmp == NULL)) {
697         /* Only get unselected neighbors. */
698         neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_LEFT, isel);
699         if (neighbor) {
700           if (sel) {
701             neighbor->flag |= SELECT;
702             recurs_sel_seq(neighbor);
703           }
704           else {
705             neighbor->flag &= ~SELECT;
706           }
707           if (!linked) {
708             neighbor->tmp = (Sequence *)1;
709           }
710           changed = true;
711         }
712         neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_RIGHT, isel);
713         if (neighbor) {
714           if (sel) {
715             neighbor->flag |= SELECT;
716             recurs_sel_seq(neighbor);
717           }
718           else {
719             neighbor->flag &= ~SELECT;
720           }
721           if (!linked) {
722             neighbor->tmp = (Sequence *)1;
723           }
724           changed = true;
725         }
726       }
727     }
728   }
729 
730   return changed;
731 }
732 
sequencer_select_more_exec(bContext * C,wmOperator * UNUSED (op))733 static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
734 {
735   Scene *scene = CTX_data_scene(C);
736 
737   if (!select_more_less_seq__internal(scene, true, false)) {
738     return OPERATOR_CANCELLED;
739   }
740 
741   ED_outliner_select_sync_from_sequence_tag(C);
742 
743   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
744 
745   return OPERATOR_FINISHED;
746 }
747 
SEQUENCER_OT_select_more(wmOperatorType * ot)748 void SEQUENCER_OT_select_more(wmOperatorType *ot)
749 {
750   /* Identifiers. */
751   ot->name = "Select More";
752   ot->idname = "SEQUENCER_OT_select_more";
753   ot->description = "Select more strips adjacent to the current selection";
754 
755   /* Api callbacks. */
756   ot->exec = sequencer_select_more_exec;
757   ot->poll = sequencer_edit_poll;
758 
759   /* Flags. */
760   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
761 }
762 
763 /** \} */
764 
765 /* -------------------------------------------------------------------- */
766 /** \name Select Less Operator
767  * \{ */
768 
sequencer_select_less_exec(bContext * C,wmOperator * UNUSED (op))769 static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
770 {
771   Scene *scene = CTX_data_scene(C);
772 
773   if (!select_more_less_seq__internal(scene, false, false)) {
774     return OPERATOR_CANCELLED;
775   }
776 
777   ED_outliner_select_sync_from_sequence_tag(C);
778 
779   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
780 
781   return OPERATOR_FINISHED;
782 }
783 
SEQUENCER_OT_select_less(wmOperatorType * ot)784 void SEQUENCER_OT_select_less(wmOperatorType *ot)
785 {
786   /* Identifiers. */
787   ot->name = "Select Less";
788   ot->idname = "SEQUENCER_OT_select_less";
789   ot->description = "Shrink the current selection of adjacent selected strips";
790 
791   /* Api callbacks. */
792   ot->exec = sequencer_select_less_exec;
793   ot->poll = sequencer_edit_poll;
794 
795   /* Flags. */
796   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
797 }
798 
799 /** \} */
800 
801 /* -------------------------------------------------------------------- */
802 /** \name Select Pick Linked Operator
803  * \{ */
804 
sequencer_select_linked_pick_invoke(bContext * C,wmOperator * op,const wmEvent * event)805 static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
806 {
807   Scene *scene = CTX_data_scene(C);
808   View2D *v2d = UI_view2d_fromcontext(C);
809 
810   bool extend = RNA_boolean_get(op->ptr, "extend");
811 
812   Sequence *mouse_seq;
813   int selected, hand;
814 
815   /* This works like UV, not mesh. */
816   mouse_seq = find_nearest_seq(scene, v2d, &hand, event->mval);
817   if (!mouse_seq) {
818     return OPERATOR_FINISHED; /* User error as with mesh?? */
819   }
820 
821   if (extend == 0) {
822     ED_sequencer_deselect_all(scene);
823   }
824 
825   mouse_seq->flag |= SELECT;
826   recurs_sel_seq(mouse_seq);
827 
828   selected = 1;
829   while (selected) {
830     selected = select_more_less_seq__internal(scene, 1, 1);
831   }
832 
833   ED_outliner_select_sync_from_sequence_tag(C);
834 
835   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
836 
837   return OPERATOR_FINISHED;
838 }
839 
SEQUENCER_OT_select_linked_pick(wmOperatorType * ot)840 void SEQUENCER_OT_select_linked_pick(wmOperatorType *ot)
841 {
842   /* Identifiers. */
843   ot->name = "Select Pick Linked";
844   ot->idname = "SEQUENCER_OT_select_linked_pick";
845   ot->description = "Select a chain of linked strips nearest to the mouse pointer";
846 
847   /* Api callbacks. */
848   ot->invoke = sequencer_select_linked_pick_invoke;
849   ot->poll = ED_operator_sequencer_active;
850 
851   /* Flags. */
852   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
853 
854   /* Properties. */
855   RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
856 }
857 
858 /** \} */
859 
860 /* -------------------------------------------------------------------- */
861 /** \name Select Linked Operator
862  * \{ */
863 
sequencer_select_linked_exec(bContext * C,wmOperator * UNUSED (op))864 static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
865 {
866   Scene *scene = CTX_data_scene(C);
867   bool selected;
868 
869   selected = true;
870   while (selected) {
871     selected = select_more_less_seq__internal(scene, true, true);
872   }
873 
874   ED_outliner_select_sync_from_sequence_tag(C);
875 
876   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
877 
878   return OPERATOR_FINISHED;
879 }
880 
SEQUENCER_OT_select_linked(wmOperatorType * ot)881 void SEQUENCER_OT_select_linked(wmOperatorType *ot)
882 {
883   /* Identifiers. */
884   ot->name = "Select Linked";
885   ot->idname = "SEQUENCER_OT_select_linked";
886   ot->description = "Select all strips adjacent to the current selection";
887 
888   /* Api callbacks. */
889   ot->exec = sequencer_select_linked_exec;
890   ot->poll = sequencer_edit_poll;
891 
892   /* Flags. */
893   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
894 }
895 
896 /** \} */
897 
898 /* -------------------------------------------------------------------- */
899 /** \name Select Handles Operator
900  * \{ */
901 
sequencer_select_handles_exec(bContext * C,wmOperator * op)902 static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
903 {
904   Scene *scene = CTX_data_scene(C);
905   Editing *ed = BKE_sequencer_editing_get(scene, false);
906   Sequence *seq;
907   int sel_side = RNA_enum_get(op->ptr, "side");
908 
909   for (seq = ed->seqbasep->first; seq; seq = seq->next) {
910     if (seq->flag & SELECT) {
911       switch (sel_side) {
912         case SEQ_SIDE_LEFT:
913           seq->flag &= ~SEQ_RIGHTSEL;
914           seq->flag |= SEQ_LEFTSEL;
915           break;
916         case SEQ_SIDE_RIGHT:
917           seq->flag &= ~SEQ_LEFTSEL;
918           seq->flag |= SEQ_RIGHTSEL;
919           break;
920         case SEQ_SIDE_BOTH:
921           seq->flag |= SEQ_LEFTSEL | SEQ_RIGHTSEL;
922           break;
923       }
924     }
925   }
926 
927   ED_outliner_select_sync_from_sequence_tag(C);
928 
929   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
930 
931   return OPERATOR_FINISHED;
932 }
933 
SEQUENCER_OT_select_handles(wmOperatorType * ot)934 void SEQUENCER_OT_select_handles(wmOperatorType *ot)
935 {
936   /* Identifiers. */
937   ot->name = "Select Handles";
938   ot->idname = "SEQUENCER_OT_select_handles";
939   ot->description = "Select gizmo handles on the sides of the selected strip";
940 
941   /* Api callbacks. */
942   ot->exec = sequencer_select_handles_exec;
943   ot->poll = sequencer_edit_poll;
944 
945   /* Flags. */
946   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
947 
948   /* Properties. */
949   RNA_def_enum(ot->srna,
950                "side",
951                prop_side_types,
952                SEQ_SIDE_BOTH,
953                "Side",
954                "The side of the handle that is selected");
955 }
956 
957 /** \} */
958 
959 /* -------------------------------------------------------------------- */
960 /** \name Select Side of Frame Operator
961  * \{ */
962 
sequencer_select_side_of_frame_exec(bContext * C,wmOperator * op)963 static int sequencer_select_side_of_frame_exec(bContext *C, wmOperator *op)
964 {
965   Scene *scene = CTX_data_scene(C);
966   Editing *ed = BKE_sequencer_editing_get(scene, false);
967   const bool extend = RNA_boolean_get(op->ptr, "extend");
968   const int side = RNA_enum_get(op->ptr, "side");
969   Sequence *seq;
970 
971   if (ed == NULL) {
972     return OPERATOR_CANCELLED;
973   }
974   if (extend == false) {
975     ED_sequencer_deselect_all(scene);
976   }
977   const int cfra = CFRA;
978   SEQ_CURRENT_BEGIN (ed, seq) {
979     bool test = false;
980     switch (side) {
981       case -1:
982         test = (cfra >= seq->enddisp);
983         break;
984       case 1:
985         test = (cfra <= seq->startdisp);
986         break;
987       case 0:
988         test = (cfra <= seq->enddisp) && (cfra >= seq->startdisp);
989         break;
990     }
991 
992     if (test) {
993       seq->flag |= SELECT;
994       recurs_sel_seq(seq);
995     }
996   }
997   SEQ_CURRENT_END;
998 
999   ED_outliner_select_sync_from_sequence_tag(C);
1000 
1001   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
1002 
1003   return OPERATOR_FINISHED;
1004 }
1005 
SEQUENCER_OT_select_side_of_frame(wmOperatorType * ot)1006 void SEQUENCER_OT_select_side_of_frame(wmOperatorType *ot)
1007 {
1008   static const EnumPropertyItem sequencer_select_left_right_types[] = {
1009       {-1, "LEFT", 0, "Left", "Select to the left of the current frame"},
1010       {1, "RIGHT", 0, "Right", "Select to the right of the current frame"},
1011       {0, NULL, 0, NULL, NULL},
1012   };
1013 
1014   /* Identifiers. */
1015   ot->name = "Select Side of Frame";
1016   ot->idname = "SEQUENCER_OT_select_side_of_frame";
1017   ot->description = "Select strips relative to the current frame";
1018 
1019   /* Api callbacks. */
1020   ot->exec = sequencer_select_side_of_frame_exec;
1021   ot->poll = ED_operator_sequencer_active;
1022 
1023   /* Flags. */
1024   ot->flag = OPTYPE_UNDO;
1025 
1026   /* Properties. */
1027   RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
1028   ot->prop = RNA_def_enum(ot->srna, "side", sequencer_select_left_right_types, 0, "Side", "");
1029 }
1030 
1031 /** \} */
1032 
1033 /* -------------------------------------------------------------------- */
1034 /** \name Select Side Operator
1035  * \{ */
1036 
sequencer_select_side_exec(bContext * C,wmOperator * op)1037 static int sequencer_select_side_exec(bContext *C, wmOperator *op)
1038 {
1039   Scene *scene = CTX_data_scene(C);
1040   Editing *ed = BKE_sequencer_editing_get(scene, false);
1041 
1042   const int sel_side = RNA_enum_get(op->ptr, "side");
1043   const int frame_init = sel_side == SEQ_SIDE_LEFT ? INT_MIN : INT_MAX;
1044   int frame_ranges[MAXSEQ];
1045   bool selected = false;
1046 
1047   copy_vn_i(frame_ranges, ARRAY_SIZE(frame_ranges), frame_init);
1048 
1049   LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
1050     if (UNLIKELY(seq->machine >= MAXSEQ)) {
1051       continue;
1052     }
1053     int *frame_limit_p = &frame_ranges[seq->machine];
1054     if (seq->flag & SELECT) {
1055       selected = true;
1056       if (sel_side == SEQ_SIDE_LEFT) {
1057         *frame_limit_p = max_ii(*frame_limit_p, seq->startdisp);
1058       }
1059       else {
1060         *frame_limit_p = min_ii(*frame_limit_p, seq->startdisp);
1061       }
1062     }
1063   }
1064 
1065   if (selected == false) {
1066     return OPERATOR_CANCELLED;
1067   }
1068 
1069   select_active_side_range(ed->seqbasep, sel_side, frame_ranges, frame_init);
1070 
1071   ED_outliner_select_sync_from_sequence_tag(C);
1072 
1073   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
1074 
1075   return OPERATOR_FINISHED;
1076 }
1077 
SEQUENCER_OT_select_side(wmOperatorType * ot)1078 void SEQUENCER_OT_select_side(wmOperatorType *ot)
1079 {
1080   /* Identifiers. */
1081   ot->name = "Select Side";
1082   ot->idname = "SEQUENCER_OT_select_side";
1083   ot->description = "Select strips on the nominated side of the selected strips";
1084 
1085   /* Api callbacks. */
1086   ot->exec = sequencer_select_side_exec;
1087   ot->poll = sequencer_edit_poll;
1088 
1089   /* Flags. */
1090   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1091 
1092   /* Properties. */
1093   RNA_def_enum(ot->srna,
1094                "side",
1095                prop_side_types,
1096                SEQ_SIDE_BOTH,
1097                "Side",
1098                "The side to which the selection is applied");
1099 }
1100 
1101 /** \} */
1102 
1103 /* -------------------------------------------------------------------- */
1104 /** \name Box Select Operator
1105  * \{ */
1106 
sequencer_box_select_exec(bContext * C,wmOperator * op)1107 static int sequencer_box_select_exec(bContext *C, wmOperator *op)
1108 {
1109   Scene *scene = CTX_data_scene(C);
1110   View2D *v2d = UI_view2d_fromcontext(C);
1111   Editing *ed = BKE_sequencer_editing_get(scene, false);
1112 
1113   if (ed == NULL) {
1114     return OPERATOR_CANCELLED;
1115   }
1116 
1117   const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode");
1118   const bool handles = RNA_boolean_get(op->ptr, "include_handles");
1119   const bool select = (sel_op != SEL_OP_SUB);
1120 
1121   if (SEL_OP_USE_PRE_DESELECT(sel_op)) {
1122     ED_sequencer_deselect_all(scene);
1123   }
1124 
1125   rctf rectf;
1126   WM_operator_properties_border_to_rctf(op, &rectf);
1127   UI_view2d_region_to_view_rctf(v2d, &rectf, &rectf);
1128 
1129   LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) {
1130     rctf rq;
1131     seq_rectf(seq, &rq);
1132     if (BLI_rctf_isect(&rq, &rectf, NULL)) {
1133       if (handles) {
1134         /* Get the handles draw size. */
1135         float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
1136         float handsize = sequence_handle_size_get_clamped(seq, pixelx);
1137 
1138         /* Right handle. */
1139         if (rectf.xmax > (seq->enddisp - handsize)) {
1140           if (select) {
1141             seq->flag |= SELECT | SEQ_RIGHTSEL;
1142           }
1143           else {
1144             /* Deselect the strip if it's left with no handles selected. */
1145             if ((seq->flag & SEQ_RIGHTSEL) && ((seq->flag & SEQ_LEFTSEL) == 0)) {
1146               seq->flag &= ~SELECT;
1147             }
1148             seq->flag &= ~SEQ_RIGHTSEL;
1149           }
1150         }
1151         /* Left handle. */
1152         if (rectf.xmin < (seq->startdisp + handsize)) {
1153           if (select) {
1154             seq->flag |= SELECT | SEQ_LEFTSEL;
1155           }
1156           else {
1157             /* Deselect the strip if it's left with no handles selected. */
1158             if ((seq->flag & SEQ_LEFTSEL) && ((seq->flag & SEQ_RIGHTSEL) == 0)) {
1159               seq->flag &= ~SELECT;
1160             }
1161             seq->flag &= ~SEQ_LEFTSEL;
1162           }
1163         }
1164       }
1165 
1166       /* Regular box selection. */
1167       else {
1168         SET_FLAG_FROM_TEST(seq->flag, select, SELECT);
1169         seq->flag &= ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
1170       }
1171     }
1172   }
1173 
1174   ED_outliner_select_sync_from_sequence_tag(C);
1175 
1176   WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
1177 
1178   return OPERATOR_FINISHED;
1179 }
1180 
sequencer_box_select_invoke(bContext * C,wmOperator * op,const wmEvent * event)1181 static int sequencer_box_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1182 {
1183   Scene *scene = CTX_data_scene(C);
1184   View2D *v2d = &CTX_wm_region(C)->v2d;
1185 
1186   const bool tweak = RNA_boolean_get(op->ptr, "tweak");
1187 
1188   if (tweak) {
1189     int hand_dummy;
1190     Sequence *seq = find_nearest_seq(scene, v2d, &hand_dummy, event->mval);
1191     if (seq != NULL) {
1192       return OPERATOR_CANCELLED | OPERATOR_PASS_THROUGH;
1193     }
1194   }
1195 
1196   return WM_gesture_box_invoke(C, op, event);
1197 }
1198 
SEQUENCER_OT_select_box(wmOperatorType * ot)1199 void SEQUENCER_OT_select_box(wmOperatorType *ot)
1200 {
1201   PropertyRNA *prop;
1202 
1203   /* Identifiers. */
1204   ot->name = "Box Select";
1205   ot->idname = "SEQUENCER_OT_select_box";
1206   ot->description = "Select strips using box selection";
1207 
1208   /* Api callbacks. */
1209   ot->invoke = sequencer_box_select_invoke;
1210   ot->exec = sequencer_box_select_exec;
1211   ot->modal = WM_gesture_box_modal;
1212   ot->cancel = WM_gesture_box_cancel;
1213 
1214   ot->poll = ED_operator_sequencer_active;
1215 
1216   /* Flags. */
1217   ot->flag = OPTYPE_UNDO;
1218 
1219   /* Properties. */
1220   WM_operator_properties_gesture_box(ot);
1221   WM_operator_properties_select_operation_simple(ot);
1222 
1223   prop = RNA_def_boolean(
1224       ot->srna, "tweak", 0, "Tweak", "Operator has been activated using a tweak event");
1225   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1226   prop = RNA_def_boolean(
1227       ot->srna, "include_handles", 0, "Select Handles", "Select the strips and their handles");
1228   RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1229 }
1230 
1231 /** \} */
1232 
1233 /* -------------------------------------------------------------------- */
1234 /** \name Select Grouped Operator
1235  * \{ */
1236 
1237 enum {
1238   SEQ_SELECT_GROUP_TYPE,
1239   SEQ_SELECT_GROUP_TYPE_BASIC,
1240   SEQ_SELECT_GROUP_TYPE_EFFECT,
1241   SEQ_SELECT_GROUP_DATA,
1242   SEQ_SELECT_GROUP_EFFECT,
1243   SEQ_SELECT_GROUP_EFFECT_LINK,
1244   SEQ_SELECT_GROUP_OVERLAP,
1245 };
1246 
1247 static const EnumPropertyItem sequencer_prop_select_grouped_types[] = {
1248     {SEQ_SELECT_GROUP_TYPE, "TYPE", 0, "Type", "Shared strip type"},
1249     {SEQ_SELECT_GROUP_TYPE_BASIC,
1250      "TYPE_BASIC",
1251      0,
1252      "Global Type",
1253      "All strips of same basic type (Graphical or Sound)"},
1254     {SEQ_SELECT_GROUP_TYPE_EFFECT,
1255      "TYPE_EFFECT",
1256      0,
1257      "Effect Type",
1258      "Shared strip effect type (if active strip is not an effect one, select all non-effect "
1259      "strips)"},
1260     {SEQ_SELECT_GROUP_DATA, "DATA", 0, "Data", "Shared data (scene, image, sound, etc.)"},
1261     {SEQ_SELECT_GROUP_EFFECT, "EFFECT", 0, "Effect", "Shared effects"},
1262     {SEQ_SELECT_GROUP_EFFECT_LINK,
1263      "EFFECT_LINK",
1264      0,
1265      "Effect/Linked",
1266      "Other strips affected by the active one (sharing some time, and below or effect-assigned)"},
1267     {SEQ_SELECT_GROUP_OVERLAP, "OVERLAP", 0, "Overlap", "Overlapping time"},
1268     {0, NULL, 0, NULL, NULL},
1269 };
1270 
1271 #define SEQ_IS_SOUND(_seq) ((_seq->type & SEQ_TYPE_SOUND_RAM) && !(_seq->type & SEQ_TYPE_EFFECT))
1272 
1273 #define SEQ_IS_EFFECT(_seq) ((_seq->type & SEQ_TYPE_EFFECT) != 0)
1274 
1275 #define SEQ_USE_DATA(_seq) \
1276   (ELEM(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq))
1277 
1278 #define SEQ_CHANNEL_CHECK(_seq, _chan) (ELEM((_chan), 0, (_seq)->machine))
1279 
select_grouped_type(Editing * ed,Sequence * actseq,const int channel)1280 static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel)
1281 {
1282   Sequence *seq;
1283   bool changed = false;
1284 
1285   SEQ_CURRENT_BEGIN (ed, seq) {
1286     if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == actseq->type) {
1287       seq->flag |= SELECT;
1288       changed = true;
1289     }
1290   }
1291   SEQ_CURRENT_END;
1292 
1293   return changed;
1294 }
1295 
select_grouped_type_basic(Editing * ed,Sequence * actseq,const int channel)1296 static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int channel)
1297 {
1298   Sequence *seq;
1299   bool changed = false;
1300   const bool is_sound = SEQ_IS_SOUND(actseq);
1301 
1302   SEQ_CURRENT_BEGIN (ed, seq) {
1303     if (SEQ_CHANNEL_CHECK(seq, channel) && (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq))) {
1304       seq->flag |= SELECT;
1305       changed = true;
1306     }
1307   }
1308   SEQ_CURRENT_END;
1309 
1310   return changed;
1311 }
1312 
select_grouped_type_effect(Editing * ed,Sequence * actseq,const int channel)1313 static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int channel)
1314 {
1315   Sequence *seq;
1316   bool changed = false;
1317   const bool is_effect = SEQ_IS_EFFECT(actseq);
1318 
1319   SEQ_CURRENT_BEGIN (ed, seq) {
1320     if (SEQ_CHANNEL_CHECK(seq, channel) &&
1321         (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq))) {
1322       seq->flag |= SELECT;
1323       changed = true;
1324     }
1325   }
1326   SEQ_CURRENT_END;
1327 
1328   return changed;
1329 }
1330 
select_grouped_data(Editing * ed,Sequence * actseq,const int channel)1331 static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel)
1332 {
1333   Sequence *seq;
1334   bool changed = false;
1335   const char *dir = actseq->strip ? actseq->strip->dir : NULL;
1336 
1337   if (!SEQ_USE_DATA(actseq)) {
1338     return changed;
1339   }
1340 
1341   if (SEQ_HAS_PATH(actseq) && dir) {
1342     SEQ_CURRENT_BEGIN (ed, seq) {
1343       if (SEQ_CHANNEL_CHECK(seq, channel) && SEQ_HAS_PATH(seq) && seq->strip &&
1344           STREQ(seq->strip->dir, dir)) {
1345         seq->flag |= SELECT;
1346         changed = true;
1347       }
1348     }
1349     SEQ_CURRENT_END;
1350   }
1351   else if (actseq->type == SEQ_TYPE_SCENE) {
1352     Scene *sce = actseq->scene;
1353     SEQ_CURRENT_BEGIN (ed, seq) {
1354       if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_SCENE && seq->scene == sce) {
1355         seq->flag |= SELECT;
1356         changed = true;
1357       }
1358     }
1359     SEQ_CURRENT_END;
1360   }
1361   else if (actseq->type == SEQ_TYPE_MOVIECLIP) {
1362     MovieClip *clip = actseq->clip;
1363     SEQ_CURRENT_BEGIN (ed, seq) {
1364       if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MOVIECLIP &&
1365           seq->clip == clip) {
1366         seq->flag |= SELECT;
1367         changed = true;
1368       }
1369     }
1370     SEQ_CURRENT_END;
1371   }
1372   else if (actseq->type == SEQ_TYPE_MASK) {
1373     struct Mask *mask = actseq->mask;
1374     SEQ_CURRENT_BEGIN (ed, seq) {
1375       if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MASK && seq->mask == mask) {
1376         seq->flag |= SELECT;
1377         changed = true;
1378       }
1379     }
1380     SEQ_CURRENT_END;
1381   }
1382 
1383   return changed;
1384 }
1385 
select_grouped_effect(Editing * ed,Sequence * actseq,const int channel)1386 static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int channel)
1387 {
1388   Sequence *seq;
1389   bool changed = false;
1390   bool effects[SEQ_TYPE_MAX + 1];
1391 
1392   for (int i = 0; i <= SEQ_TYPE_MAX; i++) {
1393     effects[i] = false;
1394   }
1395 
1396   SEQ_CURRENT_BEGIN (ed, seq) {
1397     if (SEQ_CHANNEL_CHECK(seq, channel) && (seq->type & SEQ_TYPE_EFFECT) &&
1398         ELEM(actseq, seq->seq1, seq->seq2, seq->seq3)) {
1399       effects[seq->type] = true;
1400     }
1401   }
1402   SEQ_CURRENT_END;
1403 
1404   SEQ_CURRENT_BEGIN (ed, seq) {
1405     if (SEQ_CHANNEL_CHECK(seq, channel) && effects[seq->type]) {
1406       if (seq->seq1) {
1407         seq->seq1->flag |= SELECT;
1408       }
1409       if (seq->seq2) {
1410         seq->seq2->flag |= SELECT;
1411       }
1412       if (seq->seq3) {
1413         seq->seq3->flag |= SELECT;
1414       }
1415       changed = true;
1416     }
1417   }
1418   SEQ_CURRENT_END;
1419 
1420   return changed;
1421 }
1422 
select_grouped_time_overlap(Editing * ed,Sequence * actseq)1423 static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq)
1424 {
1425   Sequence *seq;
1426   bool changed = false;
1427 
1428   SEQ_CURRENT_BEGIN (ed, seq) {
1429     if (seq->startdisp < actseq->enddisp && seq->enddisp > actseq->startdisp) {
1430       seq->flag |= SELECT;
1431       changed = true;
1432     }
1433   }
1434   SEQ_CURRENT_END;
1435 
1436   return changed;
1437 }
1438 
select_grouped_effect_link(Editing * ed,Sequence * actseq,const int channel)1439 static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int channel)
1440 {
1441   Sequence *seq = NULL;
1442   bool changed = false;
1443   const bool is_audio = ((actseq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(actseq));
1444   int startdisp = actseq->startdisp;
1445   int enddisp = actseq->enddisp;
1446   int machine = actseq->machine;
1447   SeqIterator iter;
1448 
1449   SEQ_CURRENT_BEGIN (ed, seq) {
1450     seq->tmp = NULL;
1451   }
1452   SEQ_CURRENT_END;
1453 
1454   actseq->tmp = POINTER_FROM_INT(true);
1455 
1456   for (BKE_sequence_iterator_begin(ed, &iter, true); iter.valid;
1457        BKE_sequence_iterator_next(&iter)) {
1458     seq = iter.seq;
1459 
1460     /* Ignore all seqs already selected. */
1461     /* Ignore all seqs not sharing some time with active one. */
1462     /* Ignore all seqs of incompatible types (audio vs video). */
1463     if (!SEQ_CHANNEL_CHECK(seq, channel) || (seq->flag & SELECT) || (seq->startdisp >= enddisp) ||
1464         (seq->enddisp < startdisp) || (!is_audio && SEQ_IS_SOUND(seq)) ||
1465         (is_audio && !((seq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(seq)))) {
1466       continue;
1467     }
1468 
1469     /* If the seq is an effect one, we need extra checking. */
1470     if (SEQ_IS_EFFECT(seq) && ((seq->seq1 && seq->seq1->tmp) || (seq->seq2 && seq->seq2->tmp) ||
1471                                (seq->seq3 && seq->seq3->tmp))) {
1472       if (startdisp > seq->startdisp) {
1473         startdisp = seq->startdisp;
1474       }
1475       if (enddisp < seq->enddisp) {
1476         enddisp = seq->enddisp;
1477       }
1478       if (machine < seq->machine) {
1479         machine = seq->machine;
1480       }
1481 
1482       seq->tmp = POINTER_FROM_INT(true);
1483 
1484       seq->flag |= SELECT;
1485       changed = true;
1486 
1487       /* Unfortunately, we must restart checks from the beginning. */
1488       BKE_sequence_iterator_end(&iter);
1489       BKE_sequence_iterator_begin(ed, &iter, true);
1490     }
1491 
1492     /* Video strips below active one, or any strip for audio (order doesn't matter here). */
1493     else if (seq->machine < machine || is_audio) {
1494       seq->flag |= SELECT;
1495       changed = true;
1496     }
1497   }
1498   BKE_sequence_iterator_end(&iter);
1499 
1500   return changed;
1501 }
1502 
1503 #undef SEQ_IS_SOUND
1504 #undef SEQ_IS_EFFECT
1505 #undef SEQ_USE_DATA
1506 
sequencer_select_grouped_exec(bContext * C,wmOperator * op)1507 static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
1508 {
1509   Scene *scene = CTX_data_scene(C);
1510   Editing *ed = BKE_sequencer_editing_get(scene, false);
1511   Sequence *seq, *actseq = BKE_sequencer_active_get(scene);
1512 
1513   if (actseq == NULL) {
1514     BKE_report(op->reports, RPT_ERROR, "No active sequence!");
1515     return OPERATOR_CANCELLED;
1516   }
1517 
1518   const int type = RNA_enum_get(op->ptr, "type");
1519   const int channel = RNA_boolean_get(op->ptr, "use_active_channel") ? actseq->machine : 0;
1520   const bool extend = RNA_boolean_get(op->ptr, "extend");
1521 
1522   bool changed = false;
1523 
1524   if (!extend) {
1525     SEQ_CURRENT_BEGIN (ed, seq) {
1526       seq->flag &= ~SELECT;
1527       changed = true;
1528     }
1529     SEQ_CURRENT_END;
1530   }
1531 
1532   switch (type) {
1533     case SEQ_SELECT_GROUP_TYPE:
1534       changed |= select_grouped_type(ed, actseq, channel);
1535       break;
1536     case SEQ_SELECT_GROUP_TYPE_BASIC:
1537       changed |= select_grouped_type_basic(ed, actseq, channel);
1538       break;
1539     case SEQ_SELECT_GROUP_TYPE_EFFECT:
1540       changed |= select_grouped_type_effect(ed, actseq, channel);
1541       break;
1542     case SEQ_SELECT_GROUP_DATA:
1543       changed |= select_grouped_data(ed, actseq, channel);
1544       break;
1545     case SEQ_SELECT_GROUP_EFFECT:
1546       changed |= select_grouped_effect(ed, actseq, channel);
1547       break;
1548     case SEQ_SELECT_GROUP_EFFECT_LINK:
1549       changed |= select_grouped_effect_link(ed, actseq, channel);
1550       break;
1551     case SEQ_SELECT_GROUP_OVERLAP:
1552       changed |= select_grouped_time_overlap(ed, actseq);
1553       break;
1554     default:
1555       BLI_assert(0);
1556       break;
1557   }
1558 
1559   if (changed) {
1560     ED_outliner_select_sync_from_sequence_tag(C);
1561     WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
1562     return OPERATOR_FINISHED;
1563   }
1564 
1565   return OPERATOR_CANCELLED;
1566 }
1567 
SEQUENCER_OT_select_grouped(wmOperatorType * ot)1568 void SEQUENCER_OT_select_grouped(wmOperatorType *ot)
1569 {
1570   /* Identifiers. */
1571   ot->name = "Select Grouped";
1572   ot->idname = "SEQUENCER_OT_select_grouped";
1573   ot->description = "Select all strips grouped by various properties";
1574 
1575   /* Api callbacks. */
1576   ot->invoke = WM_menu_invoke;
1577   ot->exec = sequencer_select_grouped_exec;
1578   ot->poll = sequencer_edit_poll;
1579 
1580   /* Flags. */
1581   ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1582 
1583   /* Properties. */
1584   ot->prop = RNA_def_enum(ot->srna, "type", sequencer_prop_select_grouped_types, 0, "Type", "");
1585   RNA_def_boolean(ot->srna,
1586                   "extend",
1587                   false,
1588                   "Extend",
1589                   "Extend selection instead of deselecting everything first");
1590   RNA_def_boolean(ot->srna,
1591                   "use_active_channel",
1592                   false,
1593                   "Same Channel",
1594                   "Only consider strips on the same channel as the active one");
1595 }
1596 
1597 /** \} */
1598