Cycles: svn merge -r41225:41232 ^/trunk/blender
[blender.git] / source / blender / editors / space_sequencer / sequencer_select.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation, 2003-2009, Campbell Barton
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/editors/space_sequencer/sequencer_select.c
27  *  \ingroup spseq
28  */
29
30
31 #include <stdlib.h>
32 #include <math.h>
33 #include <string.h>
34
35 #ifndef WIN32
36 #include <unistd.h>
37 #else
38 #include <io.h>
39 #endif
40 #include <sys/types.h>
41
42 #include "BLI_blenlib.h"
43 #include "BLI_math.h"
44 #include "BLI_utildefines.h"
45
46 #include "DNA_scene_types.h"
47
48 #include "BKE_context.h"
49 #include "BKE_report.h"
50 #include "BKE_sequencer.h"
51
52 #include "WM_api.h"
53 #include "WM_types.h"
54
55 #include "RNA_define.h"
56
57 /* for menu/popup icons etc etc*/
58
59 #include "ED_types.h"
60 #include "ED_screen.h"
61
62 #include "UI_view2d.h"
63
64 /* own include */
65 #include "sequencer_intern.h"
66 static void *find_nearest_marker(int UNUSED(d1), int UNUSED(d2)) {return NULL;}
67         
68 static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRING BACK */
69 {
70         Sequence *neighbor;
71         
72         neighbor=find_neighboring_sequence(scene, test, SEQ_SIDE_LEFT, -1);
73         if (neighbor) {
74                 neighbor->flag |= SELECT;
75                 recurs_sel_seq(neighbor);
76                 neighbor->flag |= SEQ_RIGHTSEL;
77         }
78         neighbor=find_neighboring_sequence(scene, test, SEQ_SIDE_RIGHT, -1);
79         if (neighbor) {
80                 neighbor->flag |= SELECT;
81                 recurs_sel_seq(neighbor);
82                 neighbor->flag |= SEQ_LEFTSEL;
83         }
84         test->flag |= SELECT;
85 }
86
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)
89 {
90         Sequence *seq;
91
92         for(seq= seqbase->first; seq; seq=seq->next) {
93                 if(channel==seq->machine) {
94                         switch(sel_side) {
95                         case SEQ_SIDE_LEFT:
96                                 if (frame > (seq->startdisp)) {
97                                         seq->flag &= ~(SEQ_RIGHTSEL|SEQ_LEFTSEL);
98                                         seq->flag |= SELECT;
99                                 }
100                                 break;
101                         case SEQ_SIDE_RIGHT:
102                                 if (frame < (seq->startdisp)) {
103                                         seq->flag &= ~(SEQ_RIGHTSEL|SEQ_LEFTSEL);
104                                         seq->flag |= SELECT;
105                                 }
106                                 break;
107                         case SEQ_SIDE_BOTH:
108                                 seq->flag &= ~(SEQ_RIGHTSEL|SEQ_LEFTSEL);
109                                 break;
110                         }
111                 }
112         }
113 }
114
115 /* used for mouse selection and for SEQUENCER_OT_select_active_side() */
116 static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
117 {
118         Sequence *seq;
119
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;
124
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);
129
130                                 recurs_sel_seq(seq);
131                         }
132                         else if(seq_link->flag & SELECT && (left_match || right_match)) {
133
134                                 /* clear for reselection */
135                                 seq->flag &= ~(SEQ_LEFTSEL|SEQ_RIGHTSEL);
136
137                                 if(left_match && seq_link->flag & SEQ_LEFTSEL)
138                                         seq->flag |= SELECT|SEQ_LEFTSEL;
139
140                                 if(right_match && seq_link->flag & SEQ_RIGHTSEL)
141                                         seq->flag |= SELECT|SEQ_RIGHTSEL;
142
143                                 recurs_sel_seq(seq);
144                         }
145                 }
146         }
147 }
148
149 #if 0 // BRING BACK
150 void select_surround_from_last(Scene *scene)
151 {
152         Sequence *seq=get_last_seq(scene);
153         
154         if (seq==NULL)
155                 return;
156         
157         select_surrounding_handles(scene, seq);
158 }
159 #endif
160
161
162 static void UNUSED_FUNCTION(select_single_seq)(Scene *scene, Sequence *seq, int deselect_all) /* BRING BACK */
163 {
164         Editing *ed= seq_give_editing(scene, FALSE);
165         
166         if(deselect_all)
167                 deselect_all_seq(scene);
168         seq_active_set(scene, seq);
169
170         if((seq->type==SEQ_IMAGE) || (seq->type==SEQ_MOVIE)) {
171                 if(seq->strip)
172                         BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
173         }
174         else if(seq->type==SEQ_SOUND) {
175                 if(seq->strip)
176                         BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
177         }
178         seq->flag|= SELECT;
179         recurs_sel_seq(seq);
180 }
181
182 // remove this function, replace with invert operator
183 //void swap_select_seq(Scene *scene)
184 #if 0
185 static void select_neighbor_from_last(Scene *scene, int lr)
186 {
187         Sequence *seq= seq_active_get(scene);
188         Sequence *neighbor;
189         int change = 0;
190         if (seq) {
191                 neighbor=find_neighboring_sequence(scene, seq, lr, -1);
192                 if (neighbor) {
193                         switch (lr) {
194                         case SEQ_SIDE_LEFT:
195                                 neighbor->flag |= SELECT;
196                                 recurs_sel_seq(neighbor);
197                                 neighbor->flag |= SEQ_RIGHTSEL;
198                                 seq->flag |= SEQ_LEFTSEL;
199                                 break;
200                         case SEQ_SIDE_RIGHT:
201                                 neighbor->flag |= SELECT;
202                                 recurs_sel_seq(neighbor);
203                                 neighbor->flag |= SEQ_LEFTSEL;
204                                 seq->flag |= SEQ_RIGHTSEL;
205                                 break;
206                         }
207                 seq->flag |= SELECT;
208                 change = 1;
209                 }
210         }
211         if (change) {
212         }
213 }
214 #endif
215
216 /* (de)select operator */
217 static int sequencer_deselect_exec(bContext *C, wmOperator *UNUSED(op))
218 {
219         Scene *scene= CTX_data_scene(C);
220         Editing *ed= seq_give_editing(scene, FALSE);
221         Sequence *seq;
222         int desel = 0;
223
224         for(seq= ed->seqbasep->first; seq; seq=seq->next) {
225                 if(seq->flag & SEQ_ALLSEL) {
226                         desel= 1;
227                         break;
228                 }
229         }
230
231         for(seq= ed->seqbasep->first; seq; seq=seq->next) {
232                 if (desel) {
233                         seq->flag &= ~SEQ_ALLSEL;
234                 }
235                 else {
236                         seq->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
237                         seq->flag |= SELECT;
238                 }
239         }
240
241         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
242         
243         return OPERATOR_FINISHED;
244 }
245
246 void SEQUENCER_OT_select_all_toggle(struct wmOperatorType *ot)
247 {
248         /* identifiers */
249         ot->name= "Select or Deselect All";
250         ot->idname= "SEQUENCER_OT_select_all_toggle";
251         ot->description="Select or deselect all strips";
252         
253         /* api callbacks */
254         ot->exec= sequencer_deselect_exec;
255         ot->poll= sequencer_edit_poll;
256         
257         /* flags */
258         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
259 }
260
261
262 /* (de)select operator */
263 static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
264 {
265         Scene *scene= CTX_data_scene(C);
266         Editing *ed= seq_give_editing(scene, FALSE);
267         Sequence *seq;
268
269         for(seq= ed->seqbasep->first; seq; seq=seq->next) {
270                 if (seq->flag & SELECT) {
271                         seq->flag &= ~SEQ_ALLSEL;
272                 }
273                 else {
274                         seq->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
275                         seq->flag |= SELECT;
276                 }
277         }
278
279         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
280         
281         return OPERATOR_FINISHED;
282 }
283
284 void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
285 {
286         /* identifiers */
287         ot->name= "Select Inverse";
288         ot->idname= "SEQUENCER_OT_select_inverse";
289         ot->description="Select unselected strips";
290         
291         /* api callbacks */
292         ot->exec= sequencer_select_inverse_exec;
293         ot->poll= sequencer_edit_poll;
294         
295         /* flags */
296         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
297 }
298
299 static int sequencer_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
300 {
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");
308         
309         Sequence *seq,*neighbor, *act_orig;
310         int hand,sel_side;
311         TimeMarker *marker;
312
313         if(ed==NULL)
314                 return OPERATOR_CANCELLED;
315         
316         marker=find_nearest_marker(SCE_MARKERS, 1); //XXX - dummy function for now
317         
318         seq= find_nearest_seq(scene, v2d, &hand, event->mval);
319
320         // XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip
321         if(seq && linked_time && left_right)
322                 left_right= FALSE;
323
324
325         if (marker) {
326                 int oldflag;
327                 /* select timeline marker */
328                 if (extend) {
329                         oldflag= marker->flag;
330                         if (oldflag & SELECT)
331                                 marker->flag &= ~SELECT;
332                         else
333                                 marker->flag |= SELECT;
334                 }
335                 else {
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;                         
338                 }
339                 
340         } else if (left_right) {
341                 /* use different logic for this */
342                 float x;
343                 deselect_all_seq(scene);
344                 UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, NULL);
345
346                 SEQP_BEGIN(ed, seq) {
347                         if (x < CFRA) {
348                                 if(seq->enddisp < CFRA) {
349                                         seq->flag |= SELECT;
350                                         recurs_sel_seq(seq);
351                                 }
352                         }
353                         else {
354                                 if(seq->startdisp > CFRA) {
355                                         seq->flag |= SELECT;
356                                         recurs_sel_seq(seq);
357                                 }
358                         }
359                 }
360                 SEQ_END
361                 
362                 {
363                         SpaceSeq *sseq= CTX_wm_space_seq(C);
364                         if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
365                                 TimeMarker *tmarker;
366
367                                 for (tmarker= scene->markers.first; tmarker; tmarker= tmarker->next) {
368                                         if(     ((x < CFRA) && tmarker->frame < CFRA) ||
369                                                 ((x >= CFRA) && tmarker->frame >= CFRA)
370                                         ) {
371                                                 tmarker->flag |= SELECT;
372                                         }
373                                         else {
374                                                 tmarker->flag &= ~SELECT;
375                                         }
376                                 }
377                         }
378                 }
379         } else {
380                 // seq= find_nearest_seq(scene, v2d, &hand, mval);
381
382                 act_orig= ed->act_seq;
383
384                 if(extend == 0 && linked_handle==0)
385                         deselect_all_seq(scene);
386         
387                 if(seq) {
388                         seq_active_set(scene, seq);
389         
390                         if ((seq->type == SEQ_IMAGE) || (seq->type == SEQ_MOVIE)) {
391                                 if(seq->strip) {
392                                         BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
393                                 }
394                         } else
395                         if (seq->type == SEQ_SOUND) {
396                                 if(seq->strip) {
397                                         BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
398                                 }
399                         }
400         
401                         if(extend && (seq->flag & SELECT) && ed->act_seq == act_orig ) {
402                                 switch(hand) {
403                                 case SEQ_SIDE_NONE:
404                                         if (linked_handle==0)
405                                                 seq->flag &= ~SEQ_ALLSEL;
406                                         break;
407                                 case SEQ_SIDE_LEFT:
408                                         seq->flag ^= SEQ_LEFTSEL;
409                                         break;
410                                 case SEQ_SIDE_RIGHT:
411                                         seq->flag ^= SEQ_RIGHTSEL;
412                                         break;
413                                 }
414                         }
415                         else {
416                                 seq->flag |= SELECT;
417                                 if(hand==SEQ_SIDE_LEFT)         seq->flag |= SEQ_LEFTSEL;
418                                 if(hand==SEQ_SIDE_RIGHT)        seq->flag |= SEQ_RIGHTSEL;
419                         }
420                         
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);
424                                 seq->flag |= SELECT;
425                                 select_surrounding_handles(scene, seq);
426                         }
427                         else if (linked_handle && ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT) && (seq->flag & SELECT)) {
428                                 /*
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.
432                                  */
433                                 sel_side= hand;
434                                 neighbor=find_neighboring_sequence(scene, seq, sel_side, -1);
435                                 if (neighbor) {
436                                         switch (sel_side) {
437                                         case SEQ_SIDE_LEFT:
438                                                 if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
439                                                         if(extend==0) deselect_all_seq(scene);
440                                                         seq->flag |= SELECT;
441                                                         
442                                                         select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
443                                                 } else {
444                                                         if(extend==0) deselect_all_seq(scene);
445                                                         seq->flag |= SELECT;
446
447                                                         neighbor->flag |= SELECT;
448                                                         recurs_sel_seq(neighbor);
449                                                         neighbor->flag |= SEQ_RIGHTSEL;
450                                                         seq->flag |= SEQ_LEFTSEL;
451                                                 }
452                                                 break;
453                                         case SEQ_SIDE_RIGHT:
454                                                 if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
455                                                         if(extend==0) deselect_all_seq(scene);
456                                                         seq->flag |= SELECT;
457
458                                                         select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
459                                                 } else {
460                                                         if(extend==0) deselect_all_seq(scene);
461                                                         seq->flag |= SELECT;
462
463                                                         neighbor->flag |= SELECT;
464                                                         recurs_sel_seq(neighbor);
465                                                         neighbor->flag |= SEQ_LEFTSEL;
466                                                         seq->flag |= SEQ_RIGHTSEL;
467                                                 }
468                                                 break;
469                                         }
470                                 } else {
471                                         if(extend==0) deselect_all_seq(scene);
472                                         select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
473                                 }
474                         }
475                         recurs_sel_seq(seq);
476
477                         if(linked_time) {
478                                 select_linked_time(ed->seqbasep, seq);
479                         }
480                 }
481         }
482         
483         /* marker transform */
484 #if 0 // XXX probably need to redo this differently for 2.5
485         if (marker) {
486                 int mval[2], xo, yo;
487 //              getmouseco_areawin(mval);
488                 xo= mval[0]; 
489                 yo= mval[1];
490                 
491                 while(get_mbut()) {             
492 //                      getmouseco_areawin(mval);
493                         if(abs(mval[0]-xo)+abs(mval[1]-yo) > 4) {
494                                 transform_markers('g', 0);
495                                 return;
496                         }
497                 }
498         }
499 #endif
500         
501         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
502
503         /* allowing tweaks */
504         return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
505 }
506
507 void SEQUENCER_OT_select(wmOperatorType *ot)
508 {
509         /* identifiers */
510         ot->name= "Activate/Select";
511         ot->idname= "SEQUENCER_OT_select";
512         ot->description="Select a strip (last selected becomes the \"active strip\")";
513         
514         /* api callbacks */
515         ot->invoke= sequencer_select_invoke;
516         ot->poll= ED_operator_sequencer_active;
517         
518         /* flags */
519         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
520         
521         /* properties */
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 current frame side the cursor is on");
526         RNA_def_boolean(ot->srna, "linked_time", 0, "Linked Time", "Select other strips at the same time");
527 }
528
529
530
531
532 /* run recursively to select linked */
533 static int select_more_less_seq__internal(Scene *scene, int sel, int linked)
534 {
535         Editing *ed= seq_give_editing(scene, FALSE);
536         Sequence *seq, *neighbor;
537         int change=0;
538         int isel;
539         
540         if(ed==NULL) return 0;
541         
542         if (sel) {
543                 sel = SELECT;
544                 isel = 0;
545         } else {
546                 sel = 0;
547                 isel = SELECT;
548         }
549         
550         if (!linked) {
551                 /* if not linked we only want to touch each seq once, newseq */
552                 for(seq= ed->seqbasep->first; seq; seq= seq->next) {
553                         seq->tmp = NULL;
554                 }
555         }
556         
557         for(seq= ed->seqbasep->first; seq; seq= seq->next) {
558                 if((int)(seq->flag & SELECT) == sel) {
559                         if ((linked==0 && seq->tmp)==0) {
560                                 /* only get unselected nabours */
561                                 neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_LEFT, isel);
562                                 if (neighbor) {
563                                         if (sel) {neighbor->flag |= SELECT; recurs_sel_seq(neighbor);}
564                                         else            neighbor->flag &= ~SELECT;
565                                         if (linked==0) neighbor->tmp = (Sequence *)1;
566                                         change = 1;
567                                 }
568                                 neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_RIGHT, isel);
569                                 if (neighbor) {
570                                         if (sel) {neighbor->flag |= SELECT; recurs_sel_seq(neighbor);}
571                                         else            neighbor->flag &= ~SELECT;
572                                         if (linked==0) neighbor->tmp = (void *)1;
573                                         change = 1;
574                                 }
575                         }
576                 }
577         }
578         
579         return change;
580 }
581
582
583
584 /* select more operator */
585 static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
586 {
587         Scene *scene= CTX_data_scene(C);
588         
589         if(!select_more_less_seq__internal(scene, 0, 0))
590                 return OPERATOR_CANCELLED;
591
592         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
593         
594         return OPERATOR_FINISHED;
595 }
596
597 void SEQUENCER_OT_select_more(wmOperatorType *ot)
598 {
599         /* identifiers */
600         ot->name= "Select More";
601         ot->idname= "SEQUENCER_OT_select_more";
602         ot->description="Select more strips adjacent to the current selection";
603         
604         /* api callbacks */
605         ot->exec= sequencer_select_more_exec;
606         ot->poll= sequencer_edit_poll;
607         
608         /* flags */
609         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
610         
611         /* properties */
612 }
613
614
615 /* select less operator */
616 static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
617 {
618         Scene *scene= CTX_data_scene(C);
619         
620         if(!select_more_less_seq__internal(scene, 1, 0))
621                 return OPERATOR_CANCELLED;
622  
623         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
624         
625         return OPERATOR_FINISHED;
626 }
627
628 void SEQUENCER_OT_select_less(wmOperatorType *ot)
629 {
630         /* identifiers */
631         ot->name= "Select Less";
632         ot->idname= "SEQUENCER_OT_select_less";
633         ot->description="Shrink the current selection of adjacent selected strips";
634         
635         /* api callbacks */
636         ot->exec= sequencer_select_less_exec;
637         ot->poll= sequencer_edit_poll;
638         
639         /* flags */
640         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
641         
642         /* properties */
643 }
644
645
646 /* select pick linked operator (uses the mouse) */
647 static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
648 {
649         Scene *scene= CTX_data_scene(C);
650         View2D *v2d= UI_view2d_fromcontext(C);
651         
652         short extend= RNA_boolean_get(op->ptr, "extend");
653         
654         Sequence *mouse_seq;
655         int selected, hand;
656
657         /* this works like UV, not mesh */
658         mouse_seq= find_nearest_seq(scene, v2d, &hand, event->mval);
659         if (!mouse_seq)
660                 return OPERATOR_FINISHED; /* user error as with mesh?? */
661         
662         if (extend==0)
663                 deselect_all_seq(scene);
664         
665         mouse_seq->flag |= SELECT;
666         recurs_sel_seq(mouse_seq);
667         
668         selected = 1;
669         while (selected) {
670                 selected = select_more_less_seq__internal(scene, 1, 1);
671         }
672         
673         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
674         
675         return OPERATOR_FINISHED;
676 }
677
678 void SEQUENCER_OT_select_linked_pick(wmOperatorType *ot)
679 {
680         /* identifiers */
681         ot->name= "Select pick linked";
682         ot->idname= "SEQUENCER_OT_select_linked_pick";
683         ot->description="Select a chain of linked strips nearest to the mouse pointer";
684         
685         /* api callbacks */
686         ot->invoke= sequencer_select_linked_pick_invoke;
687         ot->poll= ED_operator_sequencer_active;
688         
689         /* flags */
690         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
691         
692         /* properties */
693         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "extend the selection");
694 }
695
696
697 /* select linked operator */
698 static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
699 {
700         Scene *scene= CTX_data_scene(C);
701         int selected;
702
703         selected = 1;
704         while (selected) {
705                 selected = select_more_less_seq__internal(scene, 1, 1);
706         }
707
708         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
709
710         return OPERATOR_FINISHED;
711 }
712
713 void SEQUENCER_OT_select_linked(wmOperatorType *ot)
714 {
715         /* identifiers */
716         ot->name= "Select linked";
717         ot->idname= "SEQUENCER_OT_select_linked";
718         ot->description="Select all strips adjacent to the current selection";
719         
720         /* api callbacks */
721         ot->exec= sequencer_select_linked_exec;
722         ot->poll= sequencer_edit_poll;
723         
724         /* flags */
725         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
726         
727         /* properties */
728 }
729
730
731 /* select handles operator */
732 static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
733 {
734         Scene *scene= CTX_data_scene(C);
735         Editing *ed= seq_give_editing(scene, 0);
736         Sequence *seq;
737         int sel_side= RNA_enum_get(op->ptr, "side");
738
739
740         for(seq= ed->seqbasep->first; seq; seq=seq->next) {
741                 if (seq->flag & SELECT) {
742                         switch(sel_side) {
743                         case SEQ_SIDE_LEFT:
744                                 seq->flag &= ~SEQ_RIGHTSEL;
745                                 seq->flag |= SEQ_LEFTSEL;
746                                 break;
747                         case SEQ_SIDE_RIGHT:
748                                 seq->flag &= ~SEQ_LEFTSEL;
749                                 seq->flag |= SEQ_RIGHTSEL;
750                                 break;
751                         case SEQ_SIDE_BOTH:
752                                 seq->flag |= SEQ_LEFTSEL+SEQ_RIGHTSEL;
753                                 break;
754                         }
755                 }
756         }
757
758         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
759
760         return OPERATOR_FINISHED;
761 }
762
763 void SEQUENCER_OT_select_handles(wmOperatorType *ot)
764 {
765         /* identifiers */
766         ot->name= "Select Handles";
767         ot->idname= "SEQUENCER_OT_select_handles";
768         ot->description="Select manipulator handles on the sides of the selected strip";
769         
770         /* api callbacks */
771         ot->exec= sequencer_select_handles_exec;
772         ot->poll= sequencer_edit_poll;
773         
774         /* flags */
775         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
776         
777         /* properties */
778         RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side of the handle that is selected");
779 }
780
781 /* select side operator */
782 static int sequencer_select_active_side_exec(bContext *C, wmOperator *op)
783 {
784         Scene *scene= CTX_data_scene(C);
785         Editing *ed= seq_give_editing(scene, 0);
786         Sequence *seq_act= seq_active_get(scene);
787
788         if (ed==NULL || seq_act==NULL)
789                 return OPERATOR_CANCELLED;
790
791         seq_act->flag |= SELECT;
792
793         select_active_side(ed->seqbasep, RNA_enum_get(op->ptr, "side"), seq_act->machine, seq_act->startdisp);
794
795         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
796
797         return OPERATOR_FINISHED;
798 }
799
800 void SEQUENCER_OT_select_active_side(wmOperatorType *ot)
801 {
802         /* identifiers */
803         ot->name= "Select Active Side";
804         ot->idname= "SEQUENCER_OT_select_active_side";
805         ot->description="Select strips on the nominated side of the active strip";
806         
807         /* api callbacks */
808         ot->exec= sequencer_select_active_side_exec;
809         ot->poll= sequencer_edit_poll;
810
811         /* flags */
812         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
813
814         /* properties */
815         RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side of the handle that is selected");
816 }
817
818
819 /* borderselect operator */
820 static int sequencer_borderselect_exec(bContext *C, wmOperator *op)
821 {
822         Scene *scene= CTX_data_scene(C);
823         Editing *ed= seq_give_editing(scene, FALSE);
824         View2D *v2d= UI_view2d_fromcontext(C);
825         
826         Sequence *seq;
827         rcti rect;
828         rctf rectf, rq;
829         short selecting = (RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_SELECT);
830         int mval[2];
831
832         if(ed==NULL)
833                 return OPERATOR_CANCELLED;
834
835         rect.xmin= RNA_int_get(op->ptr, "xmin");
836         rect.ymin= RNA_int_get(op->ptr, "ymin");
837         rect.xmax= RNA_int_get(op->ptr, "xmax");
838         rect.ymax= RNA_int_get(op->ptr, "ymax");
839         
840         mval[0]= rect.xmin;
841         mval[1]= rect.ymin;
842         UI_view2d_region_to_view(v2d, mval[0], mval[1], &rectf.xmin, &rectf.ymin);
843         mval[0]= rect.xmax;
844         mval[1]= rect.ymax;
845         UI_view2d_region_to_view(v2d, mval[0], mval[1], &rectf.xmax, &rectf.ymax);
846
847         for(seq= ed->seqbasep->first; seq; seq= seq->next) {
848                 seq_rectf(seq, &rq);
849                 
850                 if(BLI_isect_rctf(&rq, &rectf, NULL)) {
851                         if(selecting)           seq->flag |= SELECT;
852                         else                            seq->flag &= ~SEQ_ALLSEL;
853                         recurs_sel_seq(seq);
854                 }
855         }
856
857         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
858
859         return OPERATOR_FINISHED;
860
861
862
863 /* ****** Border Select ****** */
864 void SEQUENCER_OT_select_border(wmOperatorType *ot)
865 {
866         /* identifiers */
867         ot->name= "Border Select";
868         ot->idname= "SEQUENCER_OT_select_border";
869         ot->description="Enable border select mode";
870         
871         /* api callbacks */
872         ot->invoke= WM_border_select_invoke;
873         ot->exec= sequencer_borderselect_exec;
874         ot->modal= WM_border_select_modal;
875         ot->cancel= WM_border_select_cancel;
876         
877         ot->poll= ED_operator_sequencer_active;
878         
879         /* flags */
880         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
881         
882         /* rna */
883         WM_operator_properties_gesture_border(ot, FALSE);
884 }
885
886 /* ****** Selected Grouped ****** */
887
888 static EnumPropertyItem sequencer_prop_select_grouped_types[] = {
889         {1, "TYPE", 0, "Type", "Shared strip type"},
890         {2, "TYPE_BASIC", 0, "Global Type", "All strips of same basic type (Graphical or Sound)"},
891         {3, "TYPE_EFFECT", 0, "Effect Type",
892             "Shared strip effect type (if active strip is not an effect one, select all non-effect strips)"},
893         {4, "DATA", 0, "Data", "Shared data (scene, image, sound, etc.)"},
894         {5, "EFFECT", 0, "Effect", "Shared effects"},
895         {6, "EFFECT_LINK", 0, "Effect/Linked",
896             "Other strips affected by the active one (sharing some time, and below or effect-assigned)"},
897         {7, "OVERLAP", 0, "Overlap", "Overlapping time"},
898         {0, NULL, 0, NULL, NULL}
899 };
900
901 #define SEQ_IS_SOUND(_seq) ((_seq->type & SEQ_SOUND) && !(_seq->type & SEQ_EFFECT))
902
903 #define SEQ_IS_EFFECT(_seq) (_seq->type & SEQ_EFFECT)
904
905 #define SEQ_USE_DATA(_seq) (_seq->type == SEQ_SCENE || SEQ_HAS_PATH(_seq))
906
907 static short select_grouped_type(Editing *ed, Sequence *actseq)
908 {
909         Sequence *seq;
910         short changed = FALSE;
911
912         SEQP_BEGIN(ed, seq) {
913                 if (seq->type == actseq->type) {
914                         seq->flag |= SELECT;
915                         changed = TRUE;
916                 }
917         }
918         SEQ_END;
919
920         return changed;
921 }
922
923 static short select_grouped_type_basic(Editing *ed, Sequence *actseq)
924 {
925         Sequence *seq;
926         short changed = FALSE;
927         short is_sound = SEQ_IS_SOUND(actseq);
928
929         SEQP_BEGIN(ed, seq) {
930                 if (is_sound ? SEQ_IS_SOUND(seq) : !SEQ_IS_SOUND(seq)) {
931                         seq->flag |= SELECT;
932                         changed = TRUE;
933                 }
934         }
935         SEQ_END;
936
937         return changed;
938 }
939
940 static short select_grouped_type_effect(Editing *ed, Sequence *actseq)
941 {
942         Sequence *seq;
943         short changed = FALSE;
944         short is_effect = SEQ_IS_EFFECT(actseq);
945
946         SEQP_BEGIN(ed, seq) {
947                 if (is_effect ? SEQ_IS_EFFECT(seq) : !SEQ_IS_EFFECT(seq)) {
948                         seq->flag |= SELECT;
949                         changed = TRUE;
950                 }
951         }
952         SEQ_END;
953
954         return changed;
955 }
956
957 static short select_grouped_data(Editing *ed, Sequence *actseq)
958 {
959         Sequence *seq;
960         short changed = FALSE;
961         Scene *sce = actseq->scene;
962         char *dir = actseq->strip ? actseq->strip->dir : NULL;
963
964         if (!SEQ_USE_DATA(actseq))
965                 return changed;
966
967         if (SEQ_HAS_PATH(actseq) && dir) {
968                 SEQP_BEGIN(ed, seq) {
969                         if (SEQ_HAS_PATH(seq) && seq->strip && strcmp(seq->strip->dir, dir) == 0) {
970                                 seq->flag |= SELECT;
971                                 changed = TRUE;
972                         }
973                 }
974                 SEQ_END;
975         }
976         else {
977                 SEQP_BEGIN(ed, seq) {
978                         if (seq->type == SEQ_SCENE && seq->scene == sce) {
979                                 seq->flag |= SELECT;
980                                 changed = TRUE;
981                         }
982                 }
983                 SEQ_END;
984         }
985
986         return changed;
987 }
988
989 static short select_grouped_effect(Editing *ed, Sequence *actseq)
990 {
991         Sequence *seq;
992         short changed = FALSE;
993         short effects[SEQ_EFFECT_MAX+1];
994         int i;
995
996         for (i = 0; i <= SEQ_EFFECT_MAX; i++)
997                 effects[i] = FALSE;
998
999         SEQP_BEGIN(ed, seq) {
1000                 if (ELEM3(actseq, seq->seq1, seq->seq2, seq->seq3)) {
1001                         effects[seq->type] = TRUE;
1002                 }
1003         }
1004         SEQ_END;
1005
1006         SEQP_BEGIN(ed, seq) {
1007                 if (effects[seq->type]) {
1008                         if(seq->seq1) seq->seq1->flag |= SELECT;
1009                         if(seq->seq2) seq->seq2->flag |= SELECT;
1010                         if(seq->seq3) seq->seq3->flag |= SELECT;
1011                         changed = TRUE;
1012                 }
1013         }
1014         SEQ_END;
1015
1016         return changed;
1017 }
1018
1019 static short select_grouped_time_overlap(Editing *ed, Sequence *actseq)
1020 {
1021         Sequence *seq;
1022         short changed = FALSE;
1023
1024         SEQP_BEGIN(ed, seq) {
1025                 if (!((seq->startdisp >= actseq->enddisp) || (seq->enddisp < actseq->startdisp))) {
1026                         seq->flag |= SELECT;
1027                         changed = TRUE;
1028                 }
1029         }
1030         SEQ_END;
1031
1032         return changed;
1033 }
1034
1035 static short select_grouped_effect_link(Editing *ed, Sequence *actseq)
1036 {
1037         Sequence *seq = NULL;
1038         short changed = FALSE;
1039         short is_audio = ((actseq->type == SEQ_META) || SEQ_IS_SOUND(actseq));
1040         int startdisp = actseq->startdisp;
1041         int enddisp   = actseq->enddisp;
1042         int machine   = actseq->machine;
1043         SeqIterator iter;
1044
1045         SEQP_BEGIN(ed, seq) {
1046                 seq->tmp= NULL;
1047         }
1048         SEQ_END;
1049
1050         actseq->tmp= SET_INT_IN_POINTER(TRUE);
1051
1052         for(seq_begin(ed, &iter, 1); iter.valid; seq_next(&iter)) {
1053                 seq = iter.seq;
1054
1055                 /* Ignore all seqs already selected! */
1056                 /* Ignore all seqs not sharing some time with active one. */
1057                 /* Ignore all seqs of incompatible types (audio vs video). */
1058                 if ((seq->flag & SELECT) || (seq->startdisp >= enddisp) || (seq->enddisp < startdisp)
1059                     || (!is_audio && SEQ_IS_SOUND(seq))
1060                     || (is_audio && !((seq->type == SEQ_META) || SEQ_IS_SOUND(seq))))
1061                         continue;
1062
1063                 /* If the seq is an effect one, we need extra cheking! */
1064                 if (SEQ_IS_EFFECT(seq) && ((seq->seq1 && seq->seq1->tmp) ||
1065                                            (seq->seq2 && seq->seq2->tmp) ||
1066                                            (seq->seq3 && seq->seq3->tmp)))
1067                 {
1068                         if (startdisp > seq->startdisp) startdisp = seq->startdisp;
1069                         if (enddisp < seq->enddisp) enddisp = seq->enddisp;
1070                         if (machine < seq->machine) machine = seq->machine;
1071
1072                         seq->tmp= SET_INT_IN_POINTER(TRUE);
1073
1074                         seq->flag |= SELECT;
1075                         changed = TRUE;
1076
1077                         /* Unfortunately, we must restart checks from the begining. */
1078                         seq_end(&iter);
1079                         seq_begin(ed, &iter, 1);
1080                 }
1081
1082                 /* Video strips bellow active one, or any strip for audio (order do no matters here!). */
1083                 else if (seq->machine < machine || is_audio) {
1084                         seq->flag |= SELECT;
1085                         changed = TRUE;
1086                 }
1087         }
1088         seq_end(&iter);
1089
1090         return changed;
1091 }
1092
1093 static int sequencer_select_grouped_exec(bContext *C, wmOperator *op)
1094 {
1095         Scene *scene  = CTX_data_scene(C);
1096         Editing *ed   = seq_give_editing(scene, 0);
1097         Sequence *seq, *actseq = seq_active_get(scene);
1098         int type = RNA_enum_get(op->ptr, "type");
1099         short changed = 0, extend;
1100
1101         extend = RNA_boolean_get(op->ptr, "extend");
1102
1103         if (actseq == NULL) {
1104                 BKE_report(op->reports, RPT_ERROR, "No Active Sequence!");
1105                 return OPERATOR_CANCELLED;
1106         }
1107
1108         if (extend == 0) {
1109                 SEQP_BEGIN(ed, seq) {
1110                         seq->flag &= ~SELECT;
1111                         changed = TRUE;
1112                 }
1113                 SEQ_END;
1114         }
1115
1116         if(type==1)      changed |= select_grouped_type(ed, actseq);
1117         else if(type==2) changed |= select_grouped_type_basic(ed, actseq);
1118         else if(type==3) changed |= select_grouped_type_effect(ed, actseq);
1119         else if(type==4) changed |= select_grouped_data(ed, actseq);
1120         else if(type==5) changed |= select_grouped_effect(ed, actseq);
1121         else if(type==6) changed |= select_grouped_effect_link(ed, actseq);
1122         else if(type==7) changed |= select_grouped_time_overlap(ed, actseq);
1123
1124         if (changed) {
1125                 WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
1126                 return OPERATOR_FINISHED;
1127         }
1128
1129         return OPERATOR_CANCELLED;
1130 }
1131
1132 void SEQUENCER_OT_select_grouped(wmOperatorType *ot)
1133 {
1134         /* identifiers */
1135         ot->name = "Select Grouped";
1136         ot->description = "Select all strips grouped by various properties";
1137         ot->idname = "SEQUENCER_OT_select_grouped";
1138         
1139         /* api callbacks */
1140         ot->invoke = WM_menu_invoke;
1141         ot->exec = sequencer_select_grouped_exec;
1142         ot->poll = sequencer_edit_poll;
1143         
1144         /* flags */
1145         ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
1146         
1147         /* properties */
1148         RNA_def_boolean(ot->srna, "extend", FALSE, "Extend", "Extend selection instead of deselecting everything first");
1149         ot->prop = RNA_def_enum(ot->srna, "type", sequencer_prop_select_grouped_types, 0, "Type", "");
1150 }
1151