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