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