2 * ***** BEGIN GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * Contributor(s): Blender Foundation, 2003-2009, Campbell Barton
23 * ***** END GPL LICENSE BLOCK *****
26 /** \file blender/editors/space_sequencer/sequencer_select.c
35 #include "BLI_blenlib.h"
36 #include "BLI_utildefines.h"
38 #include "DNA_scene_types.h"
40 #include "BKE_context.h"
41 #include "BKE_report.h"
42 #include "BKE_sequencer.h"
47 #include "RNA_define.h"
49 /* for menu/popup icons etc etc*/
51 #include "ED_screen.h"
52 #include "ED_sequencer.h"
54 #include "UI_view2d.h"
57 #include "sequencer_intern.h"
58 static void *find_nearest_marker(int UNUSED(d1), int UNUSED(d2))
63 static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRING BACK */
67 neighbor = find_neighboring_sequence(scene, test, SEQ_SIDE_LEFT, -1);
69 /* Only select neighbor handle if matching handle from test seq is also selected, or if neighbor
70 * was not selected at all up till now.
71 * Otherwise, we get odd mismatch when shift-alt-rmb selecting neighbor strips... */
72 if (!(neighbor->flag & SELECT) || (test->flag & SEQ_LEFTSEL)) {
73 neighbor->flag |= SEQ_RIGHTSEL;
75 neighbor->flag |= SELECT;
76 recurs_sel_seq(neighbor);
78 neighbor = find_neighboring_sequence(scene, test, SEQ_SIDE_RIGHT, -1);
80 if (!(neighbor->flag & SELECT) || (test->flag & SEQ_RIGHTSEL)) { /* See comment above. */
81 neighbor->flag |= SEQ_LEFTSEL;
83 neighbor->flag |= SELECT;
84 recurs_sel_seq(neighbor);
88 /* used for mouse selection and for SEQUENCER_OT_select_active_side() */
89 static void select_active_side(ListBase *seqbase, int sel_side, int channel, int frame)
93 for (seq = seqbase->first; seq; seq = seq->next) {
94 if (channel == seq->machine) {
97 if (frame > (seq->startdisp)) {
98 seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
103 if (frame < (seq->startdisp)) {
104 seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
109 seq->flag &= ~(SEQ_RIGHTSEL | SEQ_LEFTSEL);
117 /* used for mouse selection and for SEQUENCER_OT_select_active_side() */
118 static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
122 for (seq = seqbase->first; seq; seq = seq->next) {
123 if (seq_link->machine != seq->machine) {
124 int left_match = (seq->startdisp == seq_link->startdisp) ? 1 : 0;
125 int right_match = (seq->enddisp == seq_link->enddisp) ? 1 : 0;
127 if (left_match && right_match) {
128 /* a direct match, copy the selection settinhs */
129 seq->flag &= ~(SELECT | SEQ_LEFTSEL | SEQ_RIGHTSEL);
130 seq->flag |= seq_link->flag & (SELECT | SEQ_LEFTSEL | SEQ_RIGHTSEL);
134 else if (seq_link->flag & SELECT && (left_match || right_match)) {
136 /* clear for reselection */
137 seq->flag &= ~(SEQ_LEFTSEL | SEQ_RIGHTSEL);
139 if (left_match && seq_link->flag & SEQ_LEFTSEL)
140 seq->flag |= SELECT | SEQ_LEFTSEL;
142 if (right_match && seq_link->flag & SEQ_RIGHTSEL)
143 seq->flag |= SELECT | SEQ_RIGHTSEL;
152 void select_surround_from_last(Scene *scene)
154 Sequence *seq = get_last_seq(scene);
159 select_surrounding_handles(scene, seq);
163 void ED_sequencer_select_sequence_single(Scene *scene, Sequence *seq, bool deselect_all)
165 Editing *ed = BKE_sequencer_editing_get(scene, false);
168 ED_sequencer_deselect_all(scene);
170 BKE_sequencer_active_set(scene, seq);
172 if ((seq->type == SEQ_TYPE_IMAGE) || (seq->type == SEQ_TYPE_MOVIE)) {
174 BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
176 else if (seq->type == SEQ_TYPE_SOUND_RAM) {
178 BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
185 static void select_neighbor_from_last(Scene *scene, int lr)
187 Sequence *seq = BKE_sequencer_active_get(scene);
189 bool changed = false;
191 neighbor = find_neighboring_sequence(scene, seq, lr, -1);
195 neighbor->flag |= SELECT;
196 recurs_sel_seq(neighbor);
197 neighbor->flag |= SEQ_RIGHTSEL;
198 seq->flag |= SEQ_LEFTSEL;
201 neighbor->flag |= SELECT;
202 recurs_sel_seq(neighbor);
203 neighbor->flag |= SEQ_LEFTSEL;
204 seq->flag |= SEQ_RIGHTSEL;
216 /* (de)select operator */
217 static int sequencer_de_select_all_exec(bContext *C, wmOperator *op)
219 int action = RNA_enum_get(op->ptr, "action");
221 Scene *scene = CTX_data_scene(C);
222 Editing *ed = BKE_sequencer_editing_get(scene, false);
225 if (action == SEL_TOGGLE) {
227 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
228 if (seq->flag & SEQ_ALLSEL) {
229 action = SEL_DESELECT;
235 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
238 seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
242 seq->flag &= ~SEQ_ALLSEL;
245 if (seq->flag & SEQ_ALLSEL) {
246 seq->flag &= ~SEQ_ALLSEL;
249 seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
256 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
258 return OPERATOR_FINISHED;
261 void SEQUENCER_OT_select_all(struct wmOperatorType *ot)
264 ot->name = "(De)select All";
265 ot->idname = "SEQUENCER_OT_select_all";
266 ot->description = "Select or deselect all strips";
269 ot->exec = sequencer_de_select_all_exec;
270 ot->poll = sequencer_edit_poll;
273 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
275 WM_operator_properties_select_all(ot);
279 /* (de)select operator */
280 static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
282 Scene *scene = CTX_data_scene(C);
283 Editing *ed = BKE_sequencer_editing_get(scene, false);
286 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
287 if (seq->flag & SELECT) {
288 seq->flag &= ~SEQ_ALLSEL;
291 seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL);
296 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
298 return OPERATOR_FINISHED;
301 void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
304 ot->name = "Select Inverse";
305 ot->idname = "SEQUENCER_OT_select_inverse";
306 ot->description = "Select unselected strips";
309 ot->exec = sequencer_select_inverse_exec;
310 ot->poll = sequencer_edit_poll;
313 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
316 static int sequencer_select_invoke(bContext *C, wmOperator *op, const wmEvent *event)
318 View2D *v2d = UI_view2d_fromcontext(C);
319 Scene *scene = CTX_data_scene(C);
320 Editing *ed = BKE_sequencer_editing_get(scene, false);
321 const bool extend = RNA_boolean_get(op->ptr, "extend");
322 const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle");
323 const bool linked_time = RNA_boolean_get(op->ptr, "linked_time");
324 int left_right = RNA_enum_get(op->ptr, "left_right");
326 Sequence *seq, *neighbor, *act_orig;
331 return OPERATOR_CANCELLED;
333 marker = find_nearest_marker(SCE_MARKERS, 1); //XXX - dummy function for now
335 seq = find_nearest_seq(scene, v2d, &hand, event->mval);
337 // XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip
338 if (seq && linked_time && (left_right == SEQ_SELECT_LR_MOUSE))
339 left_right = SEQ_SELECT_LR_NONE;
344 /* select timeline marker */
346 oldflag = marker->flag;
347 if (oldflag & SELECT)
348 marker->flag &= ~SELECT;
350 marker->flag |= SELECT;
353 /* deselect_markers(0, 0); */ /* XXX, in 2.4x, seq selection used to deselect all, need to re-thnik this for 2.5 */
354 marker->flag |= SELECT;
358 else if (left_right != SEQ_SELECT_LR_NONE) {
359 /* use different logic for this */
361 ED_sequencer_deselect_all(scene);
363 switch (left_right) {
364 case SEQ_SELECT_LR_MOUSE:
365 x = UI_view2d_region_to_view_x(v2d, event->mval[0]);
367 case SEQ_SELECT_LR_LEFT:
370 case SEQ_SELECT_LR_RIGHT:
378 if (((x < CFRA) && (seq->enddisp <= CFRA)) ||
379 ((x >= CFRA) && (seq->startdisp >= CFRA)))
387 SpaceSeq *sseq = CTX_wm_space_seq(C);
388 if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
391 for (tmarker = scene->markers.first; tmarker; tmarker = tmarker->next) {
392 if (((x < CFRA) && (tmarker->frame <= CFRA)) ||
393 ((x >= CFRA) && (tmarker->frame >= CFRA)))
395 tmarker->flag |= SELECT;
398 tmarker->flag &= ~SELECT;
405 // seq = find_nearest_seq(scene, v2d, &hand, mval);
407 act_orig = ed->act_seq;
409 if (extend == 0 && linked_handle == 0)
410 ED_sequencer_deselect_all(scene);
413 BKE_sequencer_active_set(scene, seq);
415 if ((seq->type == SEQ_TYPE_IMAGE) || (seq->type == SEQ_TYPE_MOVIE)) {
417 BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
420 else if (seq->type == SEQ_TYPE_SOUND_RAM) {
422 BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
426 /* On Alt selection, select the strip and bordering handles */
428 if (!ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
429 /* First click selects the strip and its adjacent handles (if valid).
430 * Second click selects the strip, both of its handles and its adjacent handles (if valid).
432 const bool is_striponly_selected = ((seq->flag & SEQ_ALLSEL) == SELECT);
435 ED_sequencer_deselect_all(scene);
437 seq->flag &= ~SEQ_ALLSEL;
438 seq->flag |= is_striponly_selected ? SEQ_ALLSEL : SELECT;
439 select_surrounding_handles(scene, seq);
442 /* always select the strip under the cursor */
445 /* First click selects adjacent handles on that side.
446 * Second click selects all strips in that direction.
447 * If there are no adjacent strips, it just selects all in that direction.
450 neighbor = find_neighboring_sequence(scene, seq, sel_side, -1);
454 if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
455 if (extend == 0) ED_sequencer_deselect_all(scene);
458 select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
461 if (extend == 0) ED_sequencer_deselect_all(scene);
464 neighbor->flag |= SELECT;
465 recurs_sel_seq(neighbor);
466 neighbor->flag |= SEQ_RIGHTSEL;
467 seq->flag |= SEQ_LEFTSEL;
471 if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
472 if (extend == 0) ED_sequencer_deselect_all(scene);
475 select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
478 if (extend == 0) ED_sequencer_deselect_all(scene);
481 neighbor->flag |= SELECT;
482 recurs_sel_seq(neighbor);
483 neighbor->flag |= SEQ_LEFTSEL;
484 seq->flag |= SEQ_RIGHTSEL;
490 if (extend == 0) ED_sequencer_deselect_all(scene);
491 select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
496 if (extend && (seq->flag & SELECT) && ed->act_seq == act_orig) {
499 if (linked_handle == 0)
500 seq->flag &= ~SEQ_ALLSEL;
503 seq->flag ^= SEQ_LEFTSEL;
506 seq->flag ^= SEQ_RIGHTSEL;
512 if (hand == SEQ_SIDE_LEFT) seq->flag |= SEQ_LEFTSEL;
513 if (hand == SEQ_SIDE_RIGHT) seq->flag |= SEQ_RIGHTSEL;
520 select_linked_time(ed->seqbasep, seq);
525 /* marker transform */
526 #if 0 // XXX probably need to redo this differently for 2.5
529 // getmouseco_areawin(mval);
534 // getmouseco_areawin(mval);
535 if (abs(mval[0] - xo) + abs(mval[1] - yo) > 4) {
536 transform_markers('g', 0);
543 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
545 /* allowing tweaks */
546 return OPERATOR_FINISHED | OPERATOR_PASS_THROUGH;
549 void SEQUENCER_OT_select(wmOperatorType *ot)
551 static EnumPropertyItem sequencer_select_left_right_types[] = {
552 {SEQ_SELECT_LR_NONE, "NONE", 0, "None", "Don't do left-right selection"},
553 {SEQ_SELECT_LR_MOUSE, "MOUSE", 0, "Mouse", "Use mouse position for selection"},
554 {SEQ_SELECT_LR_LEFT, "LEFT", 0, "Left", "Select left"},
555 {SEQ_SELECT_LR_RIGHT, "RIGHT", 0, "Right", "Select right"},
556 {0, NULL, 0, NULL, NULL}
560 ot->name = "Activate/Select";
561 ot->idname = "SEQUENCER_OT_select";
562 ot->description = "Select a strip (last selected becomes the \"active strip\")";
565 ot->invoke = sequencer_select_invoke;
566 ot->poll = ED_operator_sequencer_active;
569 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
572 RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
573 RNA_def_boolean(ot->srna, "linked_handle", 0, "Linked Handle", "Select handles next to the active strip");
574 /* for animation this is an enum but atm having an enum isn't useful for us */
575 RNA_def_enum(ot->srna, "left_right", sequencer_select_left_right_types, 0, "Left/Right", "Select based on the current frame side the cursor is on");
576 RNA_def_boolean(ot->srna, "linked_time", 0, "Linked Time", "Select other strips at the same time");
580 /* run recursively to select linked */
581 static bool select_more_less_seq__internal(Scene *scene, bool sel, const bool linked)
583 Editing *ed = BKE_sequencer_editing_get(scene, false);
584 Sequence *seq, *neighbor;
585 bool changed = false;
601 /* if not linked we only want to touch each seq once, newseq */
602 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
607 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
608 if ((seq->flag & SELECT) == sel) {
609 if (linked || (seq->tmp == NULL)) {
610 /* only get unselected neighbors */
611 neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_LEFT, isel);
614 neighbor->flag |= SELECT;
615 recurs_sel_seq(neighbor);
618 neighbor->flag &= ~SELECT;
621 neighbor->tmp = (Sequence *)1;
625 neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_RIGHT, isel);
628 neighbor->flag |= SELECT;
629 recurs_sel_seq(neighbor);
632 neighbor->flag &= ~SELECT;
635 neighbor->tmp = (Sequence *)1;
648 /* select more operator */
649 static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
651 Scene *scene = CTX_data_scene(C);
653 if (!select_more_less_seq__internal(scene, true, false))
654 return OPERATOR_CANCELLED;
656 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
658 return OPERATOR_FINISHED;
661 void SEQUENCER_OT_select_more(wmOperatorType *ot)
664 ot->name = "Select More";
665 ot->idname = "SEQUENCER_OT_select_more";
666 ot->description = "Select more strips adjacent to the current selection";
669 ot->exec = sequencer_select_more_exec;
670 ot->poll = sequencer_edit_poll;
673 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
679 /* select less operator */
680 static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
682 Scene *scene = CTX_data_scene(C);
684 if (!select_more_less_seq__internal(scene, false, false))
685 return OPERATOR_CANCELLED;
687 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
689 return OPERATOR_FINISHED;
692 void SEQUENCER_OT_select_less(wmOperatorType *ot)
695 ot->name = "Select Less";
696 ot->idname = "SEQUENCER_OT_select_less";
697 ot->description = "Shrink the current selection of adjacent selected strips";
700 ot->exec = sequencer_select_less_exec;
701 ot->poll = sequencer_edit_poll;
704 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
710 /* select pick linked operator (uses the mouse) */
711 static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
713 Scene *scene = CTX_data_scene(C);
714 View2D *v2d = UI_view2d_fromcontext(C);
716 bool extend = RNA_boolean_get(op->ptr, "extend");
721 /* this works like UV, not mesh */
722 mouse_seq = find_nearest_seq(scene, v2d, &hand, event->mval);
724 return OPERATOR_FINISHED; /* user error as with mesh?? */
727 ED_sequencer_deselect_all(scene);
729 mouse_seq->flag |= SELECT;
730 recurs_sel_seq(mouse_seq);
734 selected = select_more_less_seq__internal(scene, 1, 1);
737 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
739 return OPERATOR_FINISHED;
742 void SEQUENCER_OT_select_linked_pick(wmOperatorType *ot)
745 ot->name = "Select Pick Linked";
746 ot->idname = "SEQUENCER_OT_select_linked_pick";
747 ot->description = "Select a chain of linked strips nearest to the mouse pointer";
750 ot->invoke = sequencer_select_linked_pick_invoke;
751 ot->poll = ED_operator_sequencer_active;
754 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
757 RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection");
761 /* select linked operator */
762 static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
764 Scene *scene = CTX_data_scene(C);
769 selected = select_more_less_seq__internal(scene, true, true);
772 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
774 return OPERATOR_FINISHED;
777 void SEQUENCER_OT_select_linked(wmOperatorType *ot)
780 ot->name = "Select Linked";
781 ot->idname = "SEQUENCER_OT_select_linked";
782 ot->description = "Select all strips adjacent to the current selection";
785 ot->exec = sequencer_select_linked_exec;
786 ot->poll = sequencer_edit_poll;
789 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
795 /* select handles operator */
796 static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
798 Scene *scene = CTX_data_scene(C);
799 Editing *ed = BKE_sequencer_editing_get(scene, false);
801 int sel_side = RNA_enum_get(op->ptr, "side");
804 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
805 if (seq->flag & SELECT) {
808 seq->flag &= ~SEQ_RIGHTSEL;
809 seq->flag |= SEQ_LEFTSEL;
812 seq->flag &= ~SEQ_LEFTSEL;
813 seq->flag |= SEQ_RIGHTSEL;
816 seq->flag |= SEQ_LEFTSEL | SEQ_RIGHTSEL;
822 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
824 return OPERATOR_FINISHED;
827 void SEQUENCER_OT_select_handles(wmOperatorType *ot)
830 ot->name = "Select Handles";
831 ot->idname = "SEQUENCER_OT_select_handles";
832 ot->description = "Select manipulator handles on the sides of the selected strip";
835 ot->exec = sequencer_select_handles_exec;
836 ot->poll = sequencer_edit_poll;
839 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
842 RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side of the handle that is selected");
845 /* select side operator */
846 static int sequencer_select_active_side_exec(bContext *C, wmOperator *op)
848 Scene *scene = CTX_data_scene(C);
849 Editing *ed = BKE_sequencer_editing_get(scene, false);
850 Sequence *seq_act = BKE_sequencer_active_get(scene);
852 if (ed == NULL || seq_act == NULL)
853 return OPERATOR_CANCELLED;
855 seq_act->flag |= SELECT;
857 select_active_side(ed->seqbasep, RNA_enum_get(op->ptr, "side"), seq_act->machine, seq_act->startdisp);
859 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
861 return OPERATOR_FINISHED;
864 void SEQUENCER_OT_select_active_side(wmOperatorType *ot)
867 ot->name = "Select Active Side";
868 ot->idname = "SEQUENCER_OT_select_active_side";
869 ot->description = "Select strips on the nominated side of the active strip";
872 ot->exec = sequencer_select_active_side_exec;
873 ot->poll = sequencer_edit_poll;
876 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
879 RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side of the handle that is selected");
883 /* borderselect operator */
884 static int sequencer_borderselect_exec(bContext *C, wmOperator *op)
886 Scene *scene = CTX_data_scene(C);
887 Editing *ed = BKE_sequencer_editing_get(scene, false);
888 View2D *v2d = UI_view2d_fromcontext(C);
892 const bool select = !RNA_boolean_get(op->ptr, "deselect");
893 const bool extend = RNA_boolean_get(op->ptr, "extend");
896 return OPERATOR_CANCELLED;
898 WM_operator_properties_border_to_rctf(op, &rectf);
899 UI_view2d_region_to_view_rctf(v2d, &rectf, &rectf);
901 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
904 if (BLI_rctf_isect(&rq, &rectf, NULL)) {
905 if (select) seq->flag |= SELECT;
906 else seq->flag &= ~SEQ_ALLSEL;
910 seq->flag &= ~SEQ_ALLSEL;
915 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
917 return OPERATOR_FINISHED;
921 /* ****** Border Select ****** */
922 void SEQUENCER_OT_select_border(wmOperatorType *ot)
925 ot->name = "Border Select";
926 ot->idname = "SEQUENCER_OT_select_border";
927 ot->description = "Select strips using border selection";
930 ot->invoke = WM_gesture_border_invoke;
931 ot->exec = sequencer_borderselect_exec;
932 ot->modal = WM_gesture_border_modal;
933 ot->cancel = WM_gesture_border_cancel;
935 ot->poll = ED_operator_sequencer_active;
938 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
941 WM_operator_properties_gesture_border_select(ot);
944 /* ****** Selected Grouped ****** */
947 SEQ_SELECT_GROUP_TYPE,
948 SEQ_SELECT_GROUP_TYPE_BASIC,
949 SEQ_SELECT_GROUP_TYPE_EFFECT,
950 SEQ_SELECT_GROUP_DATA,
951 SEQ_SELECT_GROUP_EFFECT,
952 SEQ_SELECT_GROUP_EFFECT_LINK,
953 SEQ_SELECT_GROUP_OVERLAP,
956 static EnumPropertyItem sequencer_prop_select_grouped_types[] = {
957 {SEQ_SELECT_GROUP_TYPE, "TYPE", 0, "Type", "Shared strip type"},
958 {SEQ_SELECT_GROUP_TYPE_BASIC, "TYPE_BASIC", 0, "Global Type", "All strips of same basic type (Graphical or Sound)"},
959 {SEQ_SELECT_GROUP_TYPE_EFFECT, "TYPE_EFFECT", 0, "Effect Type",
960 "Shared strip effect type (if active strip is not an effect one, select all non-effect strips)"},
961 {SEQ_SELECT_GROUP_DATA, "DATA", 0, "Data", "Shared data (scene, image, sound, etc.)"},
962 {SEQ_SELECT_GROUP_EFFECT, "EFFECT", 0, "Effect", "Shared effects"},
963 {SEQ_SELECT_GROUP_EFFECT_LINK, "EFFECT_LINK", 0, "Effect/Linked",
964 "Other strips affected by the active one (sharing some time, and below or effect-assigned)"},
965 {SEQ_SELECT_GROUP_OVERLAP, "OVERLAP", 0, "Overlap", "Overlapping time"},
966 {0, NULL, 0, NULL, NULL}
969 #define SEQ_IS_SOUND(_seq) ((_seq->type & SEQ_TYPE_SOUND_RAM) && !(_seq->type & SEQ_TYPE_EFFECT))
971 #define SEQ_IS_EFFECT(_seq) ((_seq->type & SEQ_TYPE_EFFECT) != 0)
973 #define SEQ_USE_DATA(_seq) (ELEM(_seq->type, SEQ_TYPE_SCENE, SEQ_TYPE_MOVIECLIP, SEQ_TYPE_MASK) || SEQ_HAS_PATH(_seq))
975 #define SEQ_CHANNEL_CHECK(_seq, _chan) (ELEM((_chan), 0, (_seq)->machine))
977 static bool select_grouped_type(Editing *ed, Sequence *actseq, const int channel)
980 bool changed = false;
984 if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == actseq->type) {
994 static bool select_grouped_type_basic(Editing *ed, Sequence *actseq, const int channel)
997 bool changed = false;
998 const bool is_sound = SEQ_IS_SOUND(actseq);
1000 SEQP_BEGIN (ed, seq)
1002 if (SEQ_CHANNEL_CHECK(seq, channel) && (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq))) {
1003 seq->flag |= SELECT;
1012 static bool select_grouped_type_effect(Editing *ed, Sequence *actseq, const int channel)
1015 bool changed = false;
1016 const bool is_effect = SEQ_IS_EFFECT(actseq);
1018 SEQP_BEGIN (ed, seq)
1020 if (SEQ_CHANNEL_CHECK(seq, channel) && (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq))) {
1021 seq->flag |= SELECT;
1030 static bool select_grouped_data(Editing *ed, Sequence *actseq, const int channel)
1033 bool changed = false;
1034 const char *dir = actseq->strip ? actseq->strip->dir : NULL;
1036 if (!SEQ_USE_DATA(actseq))
1039 if (SEQ_HAS_PATH(actseq) && dir) {
1040 SEQP_BEGIN (ed, seq)
1042 if (SEQ_CHANNEL_CHECK(seq, channel) && SEQ_HAS_PATH(seq) && seq->strip && STREQ(seq->strip->dir, dir)) {
1043 seq->flag |= SELECT;
1049 else if (actseq->type == SEQ_TYPE_SCENE) {
1050 Scene *sce = actseq->scene;
1051 SEQP_BEGIN (ed, seq)
1053 if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_SCENE && seq->scene == sce) {
1054 seq->flag |= SELECT;
1060 else if (actseq->type == SEQ_TYPE_MOVIECLIP) {
1061 MovieClip *clip = actseq->clip;
1062 SEQP_BEGIN (ed, seq)
1064 if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MOVIECLIP && seq->clip == clip) {
1065 seq->flag |= SELECT;
1071 else if (actseq->type == SEQ_TYPE_MASK) {
1072 struct Mask *mask = actseq->mask;
1073 SEQP_BEGIN (ed, seq)
1075 if (SEQ_CHANNEL_CHECK(seq, channel) && seq->type == SEQ_TYPE_MASK && seq->mask == mask) {
1076 seq->flag |= SELECT;
1086 static bool select_grouped_effect(Editing *ed, Sequence *actseq, const int channel)
1089 bool changed = false;
1090 bool effects[SEQ_TYPE_MAX + 1];
1093 for (i = 0; i <= SEQ_TYPE_MAX; i++)
1096 SEQP_BEGIN (ed, seq)
1098 if (SEQ_CHANNEL_CHECK(seq, channel) && (seq->type & SEQ_TYPE_EFFECT) &&
1099 ELEM(actseq, seq->seq1, seq->seq2, seq->seq3))
1101 effects[seq->type] = true;
1106 SEQP_BEGIN (ed, seq)
1108 if (SEQ_CHANNEL_CHECK(seq, channel) && effects[seq->type]) {
1109 if (seq->seq1) seq->seq1->flag |= SELECT;
1110 if (seq->seq2) seq->seq2->flag |= SELECT;
1111 if (seq->seq3) seq->seq3->flag |= SELECT;
1120 static bool select_grouped_time_overlap(Editing *ed, Sequence *actseq)
1123 bool changed = false;
1125 SEQP_BEGIN (ed, seq)
1127 if (!((seq->startdisp >= actseq->enddisp) || (seq->enddisp < actseq->startdisp))) {
1128 seq->flag |= SELECT;
1137 static bool select_grouped_effect_link(Editing *ed, Sequence *actseq, const int channel)
1139 Sequence *seq = NULL;
1140 bool changed = false;
1141 const bool is_audio = ((actseq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(actseq));
1142 int startdisp = actseq->startdisp;
1143 int enddisp = actseq->enddisp;
1144 int machine = actseq->machine;
1147 SEQP_BEGIN (ed, seq)
1153 actseq->tmp = SET_INT_IN_POINTER(true);
1155 for (BKE_sequence_iterator_begin(ed, &iter, true); iter.valid; BKE_sequence_iterator_next(&iter)) {
1158 /* Ignore all seqs already selected! */
1159 /* Ignore all seqs not sharing some time with active one. */
1160 /* Ignore all seqs of incompatible types (audio vs video). */
1161 if (!SEQ_CHANNEL_CHECK(seq, channel) ||
1162 (seq->flag & SELECT) || (seq->startdisp >= enddisp) || (seq->enddisp < startdisp) ||
1163 (!is_audio && SEQ_IS_SOUND(seq)) ||
1164 (is_audio && !((seq->type == SEQ_TYPE_META) || SEQ_IS_SOUND(seq))))
1169 /* If the seq is an effect one, we need extra cheking! */
1170 if (SEQ_IS_EFFECT(seq) && ((seq->seq1 && seq->seq1->tmp) ||
1171 (seq->seq2 && seq->seq2->tmp) ||
1172 (seq->seq3 && seq->seq3->tmp)))
1174 if (startdisp > seq->startdisp) startdisp = seq->startdisp;
1175 if (enddisp < seq->enddisp) enddisp = seq->enddisp;
1176 if (machine < seq->machine) machine = seq->machine;
1178 seq->tmp = SET_INT_IN_POINTER(true);
1180 seq->flag |= SELECT;
1183 /* Unfortunately, we must restart checks from the beginning. */
1184 BKE_sequence_iterator_end(&iter);
1185 BKE_sequence_iterator_begin(ed, &iter, true);
1188 /* Video strips bellow active one, or any strip for audio (order do no matters here!). */
1189 else if (seq->machine < machine || is_audio) {
1190 seq->flag |= SELECT;
1194 BKE_sequence_iterator_end(&iter);
1200 #undef SEQ_IS_EFFECT
1203 static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
1205 Scene *scene = CTX_data_scene(C);
1206 Editing *ed = BKE_sequencer_editing_get(scene, false);
1207 Sequence *seq, *actseq = BKE_sequencer_active_get(scene);
1209 const int type = RNA_enum_get(op->ptr, "type");
1210 const int channel = RNA_boolean_get(op->ptr, "use_active_channel") ? actseq->machine : 0;
1211 const bool extend = RNA_boolean_get(op->ptr, "extend");
1213 bool changed = false;
1215 if (actseq == NULL) {
1216 BKE_report(op->reports, RPT_ERROR, "No active sequence!");
1217 return OPERATOR_CANCELLED;
1221 SEQP_BEGIN (ed, seq)
1223 seq->flag &= ~SELECT;
1230 case SEQ_SELECT_GROUP_TYPE:
1231 changed |= select_grouped_type(ed, actseq, channel);
1233 case SEQ_SELECT_GROUP_TYPE_BASIC:
1234 changed |= select_grouped_type_basic(ed, actseq, channel);
1236 case SEQ_SELECT_GROUP_TYPE_EFFECT:
1237 changed |= select_grouped_type_effect(ed, actseq, channel);
1239 case SEQ_SELECT_GROUP_DATA:
1240 changed |= select_grouped_data(ed, actseq, channel);
1242 case SEQ_SELECT_GROUP_EFFECT:
1243 changed |= select_grouped_effect(ed, actseq, channel);
1245 case SEQ_SELECT_GROUP_EFFECT_LINK:
1246 changed |= select_grouped_effect_link(ed, actseq, channel);
1248 case SEQ_SELECT_GROUP_OVERLAP:
1249 changed |= select_grouped_time_overlap(ed, actseq);
1257 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
1258 return OPERATOR_FINISHED;
1261 return OPERATOR_CANCELLED;
1264 void SEQUENCER_OT_select_grouped(wmOperatorType *ot)
1267 ot->name = "Select Grouped";
1268 ot->description = "Select all strips grouped by various properties";
1269 ot->idname = "SEQUENCER_OT_select_grouped";
1272 ot->invoke = WM_menu_invoke;
1273 ot->exec = sequencer_select_grouped_exec;
1274 ot->poll = sequencer_edit_poll;
1277 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1280 ot->prop = RNA_def_enum(ot->srna, "type", sequencer_prop_select_grouped_types, 0, "Type", "");
1281 RNA_def_boolean(ot->srna, "extend", false, "Extend", "Extend selection instead of deselecting everything first");
1282 RNA_def_boolean(ot->srna, "use_active_channel", false, "Same Channel",
1283 "Only consider strips on the same channel as the active one");