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