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