3 * ***** BEGIN GPL LICENSE BLOCK *****
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20 * All rights reserved.
22 * Contributor(s): Blender Foundation, 2003-2009, Campbell Barton
24 * ***** END GPL LICENSE BLOCK *****
27 /** \file blender/editors/space_sequencer/sequencer_select.c
41 #include <sys/types.h>
43 #include "BLI_blenlib.h"
45 #include "BLI_utildefines.h"
47 #include "DNA_scene_types.h"
49 #include "BKE_context.h"
50 #include "BKE_sequencer.h"
55 #include "RNA_define.h"
57 /* for menu/popup icons etc etc*/
60 #include "ED_screen.h"
62 #include "UI_view2d.h"
65 #include "sequencer_intern.h"
66 static void *find_nearest_marker(int UNUSED(d1), int UNUSED(d2)) {return NULL;}
68 static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRING BACK */
72 neighbor=find_neighboring_sequence(scene, test, SEQ_SIDE_LEFT, -1);
74 neighbor->flag |= SELECT;
75 recurs_sel_seq(neighbor);
76 neighbor->flag |= SEQ_RIGHTSEL;
78 neighbor=find_neighboring_sequence(scene, test, SEQ_SIDE_RIGHT, -1);
80 neighbor->flag |= SELECT;
81 recurs_sel_seq(neighbor);
82 neighbor->flag |= SEQ_LEFTSEL;
87 /* used for mouse selection and for SEQUENCER_OT_select_active_side() */
88 static void select_active_side(ListBase *seqbase, int sel_side, int channel, int frame)
92 for(seq= seqbase->first; seq; seq=seq->next) {
93 if(channel==seq->machine) {
96 if (frame > (seq->startdisp)) {
97 seq->flag &= ~(SEQ_RIGHTSEL|SEQ_LEFTSEL);
102 if (frame < (seq->startdisp)) {
103 seq->flag &= ~(SEQ_RIGHTSEL|SEQ_LEFTSEL);
108 seq->flag &= ~(SEQ_RIGHTSEL|SEQ_LEFTSEL);
115 /* used for mouse selection and for SEQUENCER_OT_select_active_side() */
116 static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
120 for(seq= seqbase->first; seq; seq=seq->next) {
121 if(seq_link->machine != seq->machine) {
122 int left_match = (seq->startdisp == seq_link->startdisp) ? 1:0;
123 int right_match = (seq->enddisp == seq_link->enddisp) ? 1:0;
125 if(left_match && right_match) {
126 /* a direct match, copy the selection settinhs */
127 seq->flag &= ~(SELECT|SEQ_LEFTSEL|SEQ_RIGHTSEL);
128 seq->flag |= seq_link->flag & (SELECT|SEQ_LEFTSEL|SEQ_RIGHTSEL);
132 else if(seq_link->flag & SELECT && (left_match || right_match)) {
134 /* clear for reselection */
135 seq->flag &= ~(SEQ_LEFTSEL|SEQ_RIGHTSEL);
137 if(left_match && seq_link->flag & SEQ_LEFTSEL)
138 seq->flag |= SELECT|SEQ_LEFTSEL;
140 if(right_match && seq_link->flag & SEQ_RIGHTSEL)
141 seq->flag |= SELECT|SEQ_RIGHTSEL;
150 void select_surround_from_last(Scene *scene)
152 Sequence *seq=get_last_seq(scene);
157 select_surrounding_handles(scene, seq);
162 static void UNUSED_FUNCTION(select_single_seq)(Scene *scene, Sequence *seq, int deselect_all) /* BRING BACK */
164 Editing *ed= seq_give_editing(scene, FALSE);
167 deselect_all_seq(scene);
168 seq_active_set(scene, seq);
170 if((seq->type==SEQ_IMAGE) || (seq->type==SEQ_MOVIE)) {
172 strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR-1);
174 else if(seq->type==SEQ_SOUND) {
176 strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR-1);
182 // remove this function, replace with invert operator
183 //void swap_select_seq(Scene *scene)
185 static void select_neighbor_from_last(Scene *scene, int lr)
187 Sequence *seq= seq_active_get(scene);
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_deselect_exec(bContext *C, wmOperator *UNUSED(op))
219 Scene *scene= CTX_data_scene(C);
220 Editing *ed= seq_give_editing(scene, FALSE);
224 for(seq= ed->seqbasep->first; seq; seq=seq->next) {
225 if(seq->flag & SEQ_ALLSEL) {
231 for(seq= ed->seqbasep->first; seq; seq=seq->next) {
233 seq->flag &= ~SEQ_ALLSEL;
236 seq->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
241 WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
243 return OPERATOR_FINISHED;
246 void SEQUENCER_OT_select_all_toggle(struct wmOperatorType *ot)
249 ot->name= "Select or Deselect All";
250 ot->idname= "SEQUENCER_OT_select_all_toggle";
251 ot->description="Select or deselect all strips";
254 ot->exec= sequencer_deselect_exec;
255 ot->poll= sequencer_edit_poll;
258 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
262 /* (de)select operator */
263 static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
265 Scene *scene= CTX_data_scene(C);
266 Editing *ed= seq_give_editing(scene, FALSE);
269 for(seq= ed->seqbasep->first; seq; seq=seq->next) {
270 if (seq->flag & SELECT) {
271 seq->flag &= ~SEQ_ALLSEL;
274 seq->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
279 WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
281 return OPERATOR_FINISHED;
284 void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
287 ot->name= "Select Inverse";
288 ot->idname= "SEQUENCER_OT_select_inverse";
289 ot->description="Select unselected strips";
292 ot->exec= sequencer_select_inverse_exec;
293 ot->poll= sequencer_edit_poll;
296 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
299 static int sequencer_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
301 View2D *v2d= UI_view2d_fromcontext(C);
302 Scene *scene= CTX_data_scene(C);
303 Editing *ed= seq_give_editing(scene, FALSE);
304 short extend= RNA_boolean_get(op->ptr, "extend");
305 short linked_handle= RNA_boolean_get(op->ptr, "linked_handle");
306 short left_right= RNA_boolean_get(op->ptr, "left_right");
307 short linked_time= RNA_boolean_get(op->ptr, "linked_time");
309 Sequence *seq,*neighbor, *act_orig;
314 return OPERATOR_CANCELLED;
316 marker=find_nearest_marker(SCE_MARKERS, 1); //XXX - dummy function for now
318 seq= find_nearest_seq(scene, v2d, &hand, event->mval);
320 // XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip
321 if(seq && linked_time && left_right)
327 /* select timeline marker */
329 oldflag= marker->flag;
330 if (oldflag & SELECT)
331 marker->flag &= ~SELECT;
333 marker->flag |= SELECT;
336 /* deselect_markers(0, 0); */ /* XXX, in 2.4x, seq selection used to deselect all, need to re-thnik this for 2.5 */
337 marker->flag |= SELECT;
340 } else if (left_right) {
341 /* use different logic for this */
343 deselect_all_seq(scene);
344 UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, NULL);
346 SEQP_BEGIN(ed, seq) {
348 if(seq->enddisp < CFRA) {
354 if(seq->startdisp > CFRA) {
363 SpaceSeq *sseq= CTX_wm_space_seq(C);
364 if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
367 for (tmarker= scene->markers.first; tmarker; tmarker= tmarker->next) {
368 if( ((x < CFRA) && tmarker->frame < CFRA) ||
369 ((x >= CFRA) && tmarker->frame >= CFRA)
371 tmarker->flag |= SELECT;
374 tmarker->flag &= ~SELECT;
380 // seq= find_nearest_seq(scene, v2d, &hand, mval);
382 act_orig= ed->act_seq;
384 if(extend == 0 && linked_handle==0)
385 deselect_all_seq(scene);
388 seq_active_set(scene, seq);
390 if ((seq->type == SEQ_IMAGE) || (seq->type == SEQ_MOVIE)) {
392 strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR-1);
395 if (seq->type == SEQ_SOUND) {
397 strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR-1);
401 if(extend && (seq->flag & SELECT) && ed->act_seq == act_orig ) {
404 if (linked_handle==0)
405 seq->flag &= ~SEQ_ALLSEL;
408 seq->flag ^= SEQ_LEFTSEL;
411 seq->flag ^= SEQ_RIGHTSEL;
417 if(hand==SEQ_SIDE_LEFT) seq->flag |= SEQ_LEFTSEL;
418 if(hand==SEQ_SIDE_RIGHT) seq->flag |= SEQ_RIGHTSEL;
421 /* On Alt selection, select the strip and bordering handles */
422 if (linked_handle && !ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
423 if(extend==0) deselect_all_seq(scene);
425 select_surrounding_handles(scene, seq);
427 else if (linked_handle && ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT) && (seq->flag & SELECT)) {
429 * First click selects adjacent handles on that side.
430 * Second click selects all strips in that direction.
431 * If there are no adjacent strips, it just selects all in that direction.
434 neighbor=find_neighboring_sequence(scene, seq, sel_side, -1);
438 if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
439 if(extend==0) deselect_all_seq(scene);
442 select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
444 if(extend==0) deselect_all_seq(scene);
447 neighbor->flag |= SELECT;
448 recurs_sel_seq(neighbor);
449 neighbor->flag |= SEQ_RIGHTSEL;
450 seq->flag |= SEQ_LEFTSEL;
454 if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
455 if(extend==0) deselect_all_seq(scene);
458 select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
460 if(extend==0) deselect_all_seq(scene);
463 neighbor->flag |= SELECT;
464 recurs_sel_seq(neighbor);
465 neighbor->flag |= SEQ_LEFTSEL;
466 seq->flag |= SEQ_RIGHTSEL;
471 if(extend==0) deselect_all_seq(scene);
472 select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
478 select_linked_time(ed->seqbasep, seq);
483 /* marker transform */
484 #if 0 // XXX probably need to redo this differently for 2.5
487 // getmouseco_areawin(mval);
492 // getmouseco_areawin(mval);
493 if(abs(mval[0]-xo)+abs(mval[1]-yo) > 4) {
494 transform_markers('g', 0);
501 WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
503 /* allowing tweaks */
504 return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
507 void SEQUENCER_OT_select(wmOperatorType *ot)
510 ot->name= "Activate/Select";
511 ot->idname= "SEQUENCER_OT_select";
512 ot->description="Select a strip (last selected becomes the \"active strip\")";
515 ot->invoke= sequencer_select_invoke;
516 ot->poll= ED_operator_sequencer_active;
519 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
522 RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection.");
523 RNA_def_boolean(ot->srna, "linked_handle", 0, "Linked Handle", "Select handles next to the active strip.");
524 /* for animation this is an enum but atm having an enum isnt useful for us */
525 RNA_def_boolean(ot->srna, "left_right", 0, "Left/Right", "select based on the frame side the cursor is on.");
526 RNA_def_boolean(ot->srna, "linked_time", 0, "Linked Time", "Select other strips at the same time.");
532 /* run recursivly to select linked */
533 static int select_more_less_seq__internal(Scene *scene, int sel, int linked) {
534 Editing *ed= seq_give_editing(scene, FALSE);
535 Sequence *seq, *neighbor;
539 if(ed==NULL) return 0;
550 /* if not linked we only want to touch each seq once, newseq */
551 for(seq= ed->seqbasep->first; seq; seq= seq->next) {
556 for(seq= ed->seqbasep->first; seq; seq= seq->next) {
557 if((int)(seq->flag & SELECT) == sel) {
558 if ((linked==0 && seq->tmp)==0) {
559 /* only get unselected nabours */
560 neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_LEFT, isel);
562 if (sel) {neighbor->flag |= SELECT; recurs_sel_seq(neighbor);}
563 else neighbor->flag &= ~SELECT;
564 if (linked==0) neighbor->tmp = (Sequence *)1;
567 neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_RIGHT, isel);
569 if (sel) {neighbor->flag |= SELECT; recurs_sel_seq(neighbor);}
570 else neighbor->flag &= ~SELECT;
571 if (linked==0) neighbor->tmp = (void *)1;
583 /* select more operator */
584 static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
586 Scene *scene= CTX_data_scene(C);
588 if(!select_more_less_seq__internal(scene, 0, 0))
589 return OPERATOR_CANCELLED;
591 WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
593 return OPERATOR_FINISHED;
596 void SEQUENCER_OT_select_more(wmOperatorType *ot)
599 ot->name= "Select More";
600 ot->idname= "SEQUENCER_OT_select_more";
601 ot->description="Select more strips adjacent to the current selection";
604 ot->exec= sequencer_select_more_exec;
605 ot->poll= sequencer_edit_poll;
608 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
614 /* select less operator */
615 static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
617 Scene *scene= CTX_data_scene(C);
619 if(!select_more_less_seq__internal(scene, 1, 0))
620 return OPERATOR_CANCELLED;
622 WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
624 return OPERATOR_FINISHED;
627 void SEQUENCER_OT_select_less(wmOperatorType *ot)
630 ot->name= "Select less";
631 ot->idname= "SEQUENCER_OT_select_less";
632 ot->description="Shrink the current selection of adjacent selected strips";
635 ot->exec= sequencer_select_less_exec;
636 ot->poll= sequencer_edit_poll;
639 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
645 /* select pick linked operator (uses the mouse) */
646 static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
648 Scene *scene= CTX_data_scene(C);
649 View2D *v2d= UI_view2d_fromcontext(C);
651 short extend= RNA_boolean_get(op->ptr, "extend");
656 /* this works like UV, not mesh */
657 mouse_seq= find_nearest_seq(scene, v2d, &hand, event->mval);
659 return OPERATOR_FINISHED; /* user error as with mesh?? */
662 deselect_all_seq(scene);
664 mouse_seq->flag |= SELECT;
665 recurs_sel_seq(mouse_seq);
669 selected = select_more_less_seq__internal(scene, 1, 1);
672 WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
674 return OPERATOR_FINISHED;
677 void SEQUENCER_OT_select_linked_pick(wmOperatorType *ot)
680 ot->name= "Select pick linked";
681 ot->idname= "SEQUENCER_OT_select_linked_pick";
682 ot->description="Select a chain of linked strips nearest to the mouse pointer";
685 ot->invoke= sequencer_select_linked_pick_invoke;
686 ot->poll= ED_operator_sequencer_active;
689 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
692 RNA_def_boolean(ot->srna, "extend", 0, "Extend", "extend the selection");
696 /* select linked operator */
697 static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
699 Scene *scene= CTX_data_scene(C);
704 selected = select_more_less_seq__internal(scene, 1, 1);
707 WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
709 return OPERATOR_FINISHED;
712 void SEQUENCER_OT_select_linked(wmOperatorType *ot)
715 ot->name= "Select linked";
716 ot->idname= "SEQUENCER_OT_select_linked";
717 ot->description="Select all strips adjacent to the current selection";
720 ot->exec= sequencer_select_linked_exec;
721 ot->poll= sequencer_edit_poll;
724 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
730 /* select handles operator */
731 static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
733 Scene *scene= CTX_data_scene(C);
734 Editing *ed= seq_give_editing(scene, 0);
736 int sel_side= RNA_enum_get(op->ptr, "side");
739 for(seq= ed->seqbasep->first; seq; seq=seq->next) {
740 if (seq->flag & SELECT) {
743 seq->flag &= ~SEQ_RIGHTSEL;
744 seq->flag |= SEQ_LEFTSEL;
747 seq->flag &= ~SEQ_LEFTSEL;
748 seq->flag |= SEQ_RIGHTSEL;
751 seq->flag |= SEQ_LEFTSEL+SEQ_RIGHTSEL;
757 WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
759 return OPERATOR_FINISHED;
762 void SEQUENCER_OT_select_handles(wmOperatorType *ot)
765 ot->name= "Select Handles";
766 ot->idname= "SEQUENCER_OT_select_handles";
767 ot->description="Select manipulator handles on the sides of the selected strip";
770 ot->exec= sequencer_select_handles_exec;
771 ot->poll= sequencer_edit_poll;
774 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
777 RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side of the handle that is selected");
780 /* select side operator */
781 static int sequencer_select_active_side_exec(bContext *C, wmOperator *op)
783 Scene *scene= CTX_data_scene(C);
784 Editing *ed= seq_give_editing(scene, 0);
785 Sequence *seq_act= seq_active_get(scene);
787 if (ed==NULL || seq_act==NULL)
788 return OPERATOR_CANCELLED;
790 seq_act->flag |= SELECT;
792 select_active_side(ed->seqbasep, RNA_enum_get(op->ptr, "side"), seq_act->machine, seq_act->startdisp);
794 WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
796 return OPERATOR_FINISHED;
799 void SEQUENCER_OT_select_active_side(wmOperatorType *ot)
802 ot->name= "Select Active Side";
803 ot->idname= "SEQUENCER_OT_select_active_side";
804 ot->description="Select strips on the nominated side of the active strip";
807 ot->exec= sequencer_select_active_side_exec;
808 ot->poll= sequencer_edit_poll;
811 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
814 RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side of the handle that is selected");
818 /* borderselect operator */
819 static int sequencer_borderselect_exec(bContext *C, wmOperator *op)
821 Scene *scene= CTX_data_scene(C);
822 Editing *ed= seq_give_editing(scene, FALSE);
823 View2D *v2d= UI_view2d_fromcontext(C);
828 short selecting = (RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_SELECT);
832 return OPERATOR_CANCELLED;
834 rect.xmin= RNA_int_get(op->ptr, "xmin");
835 rect.ymin= RNA_int_get(op->ptr, "ymin");
836 rect.xmax= RNA_int_get(op->ptr, "xmax");
837 rect.ymax= RNA_int_get(op->ptr, "ymax");
841 UI_view2d_region_to_view(v2d, mval[0], mval[1], &rectf.xmin, &rectf.ymin);
844 UI_view2d_region_to_view(v2d, mval[0], mval[1], &rectf.xmax, &rectf.ymax);
846 for(seq= ed->seqbasep->first; seq; seq= seq->next) {
849 if(BLI_isect_rctf(&rq, &rectf, NULL)) {
850 if(selecting) seq->flag |= SELECT;
851 else seq->flag &= ~SEQ_ALLSEL;
856 WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
858 return OPERATOR_FINISHED;
862 /* ****** Border Select ****** */
863 void SEQUENCER_OT_select_border(wmOperatorType *ot)
866 ot->name= "Border Select";
867 ot->idname= "SEQUENCER_OT_select_border";
868 ot->description="Enable border select mode";
871 ot->invoke= WM_border_select_invoke;
872 ot->exec= sequencer_borderselect_exec;
873 ot->modal= WM_border_select_modal;
874 ot->cancel= WM_border_select_cancel;
876 ot->poll= ED_operator_sequencer_active;
879 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
882 WM_operator_properties_gesture_border(ot, FALSE);