doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / blender / editors / space_sequencer / sequencer_select.c
1 /*
2  *
3  * ***** BEGIN GPL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * Contributor(s): Blender Foundation, 2003-2009, Campbell Barton
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 #include <stdlib.h>
28 #include <math.h>
29 #include <string.h>
30
31 #ifndef WIN32
32 #include <unistd.h>
33 #else
34 #include <io.h>
35 #endif
36 #include <sys/types.h>
37
38 #include "BLI_blenlib.h"
39 #include "BLI_math.h"
40 #include "BLI_utildefines.h"
41
42 #include "DNA_scene_types.h"
43
44 #include "BKE_context.h"
45 #include "BKE_sequencer.h"
46
47 #include "WM_api.h"
48 #include "WM_types.h"
49
50 #include "RNA_define.h"
51
52 /* for menu/popup icons etc etc*/
53
54 #include "ED_types.h"
55 #include "ED_screen.h"
56
57 #include "UI_view2d.h"
58
59 /* own include */
60 #include "sequencer_intern.h"
61 static void *find_nearest_marker(int UNUSED(d1), int UNUSED(d2)) {return NULL;}
62         
63 static void select_surrounding_handles(Scene *scene, Sequence *test) /* XXX BRING BACK */
64 {
65         Sequence *neighbor;
66         
67         neighbor=find_neighboring_sequence(scene, test, SEQ_SIDE_LEFT, -1);
68         if (neighbor) {
69                 neighbor->flag |= SELECT;
70                 recurs_sel_seq(neighbor);
71                 neighbor->flag |= SEQ_RIGHTSEL;
72         }
73         neighbor=find_neighboring_sequence(scene, test, SEQ_SIDE_RIGHT, -1);
74         if (neighbor) {
75                 neighbor->flag |= SELECT;
76                 recurs_sel_seq(neighbor);
77                 neighbor->flag |= SEQ_LEFTSEL;
78         }
79         test->flag |= SELECT;
80 }
81
82 /* used for mouse selection and for SEQUENCER_OT_select_active_side() */
83 static void select_active_side(ListBase *seqbase, int sel_side, int channel, int frame)
84 {
85         Sequence *seq;
86
87         for(seq= seqbase->first; seq; seq=seq->next) {
88                 if(channel==seq->machine) {
89                         switch(sel_side) {
90                         case SEQ_SIDE_LEFT:
91                                 if (frame > (seq->startdisp)) {
92                                         seq->flag &= ~(SEQ_RIGHTSEL|SEQ_LEFTSEL);
93                                         seq->flag |= SELECT;
94                                 }
95                                 break;
96                         case SEQ_SIDE_RIGHT:
97                                 if (frame < (seq->startdisp)) {
98                                         seq->flag &= ~(SEQ_RIGHTSEL|SEQ_LEFTSEL);
99                                         seq->flag |= SELECT;
100                                 }
101                                 break;
102                         case SEQ_SIDE_BOTH:
103                                 seq->flag &= ~(SEQ_RIGHTSEL|SEQ_LEFTSEL);
104                                 break;
105                         }
106                 }
107         }
108 }
109
110 /* used for mouse selection and for SEQUENCER_OT_select_active_side() */
111 static void select_linked_time(ListBase *seqbase, Sequence *seq_link)
112 {
113         Sequence *seq;
114
115         for(seq= seqbase->first; seq; seq=seq->next) {
116                 if(seq_link->machine != seq->machine) {
117                         int left_match = (seq->startdisp == seq_link->startdisp) ? 1:0;
118                         int right_match = (seq->enddisp == seq_link->enddisp) ? 1:0;
119
120                         if(left_match && right_match) {
121                                 /* a direct match, copy the selection settinhs */
122                                 seq->flag &= ~(SELECT|SEQ_LEFTSEL|SEQ_RIGHTSEL);
123                                 seq->flag |= seq_link->flag & (SELECT|SEQ_LEFTSEL|SEQ_RIGHTSEL);
124
125                                 recurs_sel_seq(seq);
126                         }
127                         else if(seq_link->flag & SELECT && (left_match || right_match)) {
128
129                                 /* clear for reselection */
130                                 seq->flag &= ~(SEQ_LEFTSEL|SEQ_RIGHTSEL);
131
132                                 if(left_match && seq_link->flag & SEQ_LEFTSEL)
133                                         seq->flag |= SELECT|SEQ_LEFTSEL;
134
135                                 if(right_match && seq_link->flag & SEQ_RIGHTSEL)
136                                         seq->flag |= SELECT|SEQ_RIGHTSEL;
137
138                                 recurs_sel_seq(seq);
139                         }
140                 }
141         }
142 }
143
144 #if 0 // BRING BACK
145 void select_surround_from_last(Scene *scene)
146 {
147         Sequence *seq=get_last_seq(scene);
148         
149         if (seq==NULL)
150                 return;
151         
152         select_surrounding_handles(scene, seq);
153 }
154 #endif
155
156
157 static void select_single_seq(Scene *scene, Sequence *seq, int deselect_all) /* BRING BACK */
158 {
159         Editing *ed= seq_give_editing(scene, FALSE);
160         
161         if(deselect_all)
162                 deselect_all_seq(scene);
163         seq_active_set(scene, seq);
164
165         if((seq->type==SEQ_IMAGE) || (seq->type==SEQ_MOVIE)) {
166                 if(seq->strip)
167                         strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR-1);
168         }
169         else if(seq->type==SEQ_SOUND) {
170                 if(seq->strip)
171                         strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR-1);
172         }
173         seq->flag|= SELECT;
174         recurs_sel_seq(seq);
175 }
176
177 // remove this function, replace with invert operator
178 //void swap_select_seq(Scene *scene)
179 #if 0
180 static void select_neighbor_from_last(Scene *scene, int lr)
181 {
182         Sequence *seq= seq_active_get(scene);
183         Sequence *neighbor;
184         int change = 0;
185         if (seq) {
186                 neighbor=find_neighboring_sequence(scene, seq, lr, -1);
187                 if (neighbor) {
188                         switch (lr) {
189                         case SEQ_SIDE_LEFT:
190                                 neighbor->flag |= SELECT;
191                                 recurs_sel_seq(neighbor);
192                                 neighbor->flag |= SEQ_RIGHTSEL;
193                                 seq->flag |= SEQ_LEFTSEL;
194                                 break;
195                         case SEQ_SIDE_RIGHT:
196                                 neighbor->flag |= SELECT;
197                                 recurs_sel_seq(neighbor);
198                                 neighbor->flag |= SEQ_LEFTSEL;
199                                 seq->flag |= SEQ_RIGHTSEL;
200                                 break;
201                         }
202                 seq->flag |= SELECT;
203                 change = 1;
204                 }
205         }
206         if (change) {
207         }
208 }
209 #endif
210
211 /* (de)select operator */
212 static int sequencer_deselect_exec(bContext *C, wmOperator *UNUSED(op))
213 {
214         Scene *scene= CTX_data_scene(C);
215         Editing *ed= seq_give_editing(scene, FALSE);
216         Sequence *seq;
217         int desel = 0;
218
219         for(seq= ed->seqbasep->first; seq; seq=seq->next) {
220                 if(seq->flag & SEQ_ALLSEL) {
221                         desel= 1;
222                         break;
223                 }
224         }
225
226         for(seq= ed->seqbasep->first; seq; seq=seq->next) {
227                 if (desel) {
228                         seq->flag &= ~SEQ_ALLSEL;
229                 }
230                 else {
231                         seq->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
232                         seq->flag |= SELECT;
233                 }
234         }
235
236         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
237         
238         return OPERATOR_FINISHED;
239 }
240
241 void SEQUENCER_OT_select_all_toggle(struct wmOperatorType *ot)
242 {
243         /* identifiers */
244         ot->name= "Select or Deselect All";
245         ot->idname= "SEQUENCER_OT_select_all_toggle";
246         ot->description="Select or deselect all strips";
247         
248         /* api callbacks */
249         ot->exec= sequencer_deselect_exec;
250         ot->poll= sequencer_edit_poll;
251         
252         /* flags */
253         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
254 }
255
256
257 /* (de)select operator */
258 static int sequencer_select_inverse_exec(bContext *C, wmOperator *UNUSED(op))
259 {
260         Scene *scene= CTX_data_scene(C);
261         Editing *ed= seq_give_editing(scene, FALSE);
262         Sequence *seq;
263
264         for(seq= ed->seqbasep->first; seq; seq=seq->next) {
265                 if (seq->flag & SELECT) {
266                         seq->flag &= ~SEQ_ALLSEL;
267                 }
268                 else {
269                         seq->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL);
270                         seq->flag |= SELECT;
271                 }
272         }
273
274         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
275         
276         return OPERATOR_FINISHED;
277 }
278
279 void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
280 {
281         /* identifiers */
282         ot->name= "Select Inverse";
283         ot->idname= "SEQUENCER_OT_select_inverse";
284         ot->description="Select unselected strips";
285         
286         /* api callbacks */
287         ot->exec= sequencer_select_inverse_exec;
288         ot->poll= sequencer_edit_poll;
289         
290         /* flags */
291         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
292 }
293
294 static int sequencer_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
295 {
296         ARegion *ar= CTX_wm_region(C);
297         View2D *v2d= UI_view2d_fromcontext(C);
298         Scene *scene= CTX_data_scene(C);
299         Editing *ed= seq_give_editing(scene, FALSE);
300         short extend= RNA_boolean_get(op->ptr, "extend");
301         short linked_handle= RNA_boolean_get(op->ptr, "linked_handle");
302         short left_right= RNA_boolean_get(op->ptr, "left_right");
303         short linked_time= RNA_boolean_get(op->ptr, "linked_time");
304
305         short mval[2];  
306         
307         Sequence *seq,*neighbor, *act_orig;
308         int hand,sel_side;
309         TimeMarker *marker;
310
311         if(ed==NULL)
312                 return OPERATOR_CANCELLED;
313         
314         marker=find_nearest_marker(SCE_MARKERS, 1); //XXX - dummy function for now
315         
316         mval[0]= event->x - ar->winrct.xmin;
317         mval[1]= event->y - ar->winrct.ymin;
318         
319         seq= find_nearest_seq(scene, v2d, &hand, mval);
320
321         // XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip
322         if(seq && linked_time && left_right)
323                 left_right= FALSE;
324
325
326         if (marker) {
327                 int oldflag;
328                 /* select timeline marker */
329                 if (extend) {
330                         oldflag= marker->flag;
331                         if (oldflag & SELECT)
332                                 marker->flag &= ~SELECT;
333                         else
334                                 marker->flag |= SELECT;
335                 }
336                 else {
337                         /* deselect_markers(0, 0); */ /* XXX, in 2.4x, seq selection used to deselect all, need to re-thnik this for 2.5 */
338                         marker->flag |= SELECT;                         
339                 }
340                 
341         } else if (left_right) {
342                 /* use different logic for this */
343                 float x;
344                 deselect_all_seq(scene);
345                 UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, NULL);
346
347                 SEQP_BEGIN(ed, seq) {
348                         if (x < CFRA) {
349                                 if(seq->enddisp < CFRA) {
350                                         seq->flag |= SELECT;
351                                         recurs_sel_seq(seq);
352                                 }
353                         }
354                         else {
355                                 if(seq->startdisp > CFRA) {
356                                         seq->flag |= SELECT;
357                                         recurs_sel_seq(seq);
358                                 }
359                         }
360                 }
361                 SEQ_END
362                 
363                 {
364                         SpaceSeq *sseq= CTX_wm_space_seq(C);
365                         if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
366                                 TimeMarker *tmarker;
367
368                                 for (tmarker= scene->markers.first; tmarker; tmarker= tmarker->next) {
369                                         if(     ((x < CFRA) && tmarker->frame < CFRA) ||
370                                                 ((x >= CFRA) && tmarker->frame >= CFRA)
371                                         ) {
372                                                 tmarker->flag |= SELECT;
373                                         }
374                                         else {
375                                                 tmarker->flag &= ~SELECT;
376                                         }
377                                 }
378                         }
379                 }
380         } else {
381                 // seq= find_nearest_seq(scene, v2d, &hand, mval);
382
383                 act_orig= ed->act_seq;
384
385                 if(extend == 0 && linked_handle==0)
386                         deselect_all_seq(scene);
387         
388                 if(seq) {
389                         seq_active_set(scene, seq);
390         
391                         if ((seq->type == SEQ_IMAGE) || (seq->type == SEQ_MOVIE)) {
392                                 if(seq->strip) {
393                                         strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR-1);
394                                 }
395                         } else
396                         if (seq->type == SEQ_SOUND) {
397                                 if(seq->strip) {
398                                         strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR-1);
399                                 }
400                         }
401         
402                         if(extend && (seq->flag & SELECT) && ed->act_seq == act_orig ) {
403                                 switch(hand) {
404                                 case SEQ_SIDE_NONE:
405                                         if (linked_handle==0)
406                                                 seq->flag &= ~SEQ_ALLSEL;
407                                         break;
408                                 case SEQ_SIDE_LEFT:
409                                         seq->flag ^= SEQ_LEFTSEL;
410                                         break;
411                                 case SEQ_SIDE_RIGHT:
412                                         seq->flag ^= SEQ_RIGHTSEL;
413                                         break;
414                                 }
415                         }
416                         else {
417                                 seq->flag |= SELECT;
418                                 if(hand==SEQ_SIDE_LEFT)         seq->flag |= SEQ_LEFTSEL;
419                                 if(hand==SEQ_SIDE_RIGHT)        seq->flag |= SEQ_RIGHTSEL;
420                         }
421                         
422                         /* On Alt selection, select the strip and bordering handles */
423                         if (linked_handle && !ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
424                                 if(extend==0) deselect_all_seq(scene);
425                                 seq->flag |= SELECT;
426                                 select_surrounding_handles(scene, seq);
427                         }
428                         else if (linked_handle && ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT) && (seq->flag & SELECT)) {
429                                 /*
430                                  * First click selects adjacent handles on that side.
431                                  * Second click selects all strips in that direction.
432                                  * If there are no adjacent strips, it just selects all in that direction.
433                                  */
434                                 sel_side= hand;
435                                 neighbor=find_neighboring_sequence(scene, seq, sel_side, -1);
436                                 if (neighbor) {
437                                         switch (sel_side) {
438                                         case SEQ_SIDE_LEFT:
439                                                 if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
440                                                         if(extend==0) deselect_all_seq(scene);
441                                                         seq->flag |= SELECT;
442                                                         
443                                                         select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
444                                                 } else {
445                                                         if(extend==0) deselect_all_seq(scene);
446                                                         seq->flag |= SELECT;
447
448                                                         neighbor->flag |= SELECT;
449                                                         recurs_sel_seq(neighbor);
450                                                         neighbor->flag |= SEQ_RIGHTSEL;
451                                                         seq->flag |= SEQ_LEFTSEL;
452                                                 }
453                                                 break;
454                                         case SEQ_SIDE_RIGHT:
455                                                 if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
456                                                         if(extend==0) deselect_all_seq(scene);
457                                                         seq->flag |= SELECT;
458
459                                                         select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
460                                                 } else {
461                                                         if(extend==0) deselect_all_seq(scene);
462                                                         seq->flag |= SELECT;
463
464                                                         neighbor->flag |= SELECT;
465                                                         recurs_sel_seq(neighbor);
466                                                         neighbor->flag |= SEQ_LEFTSEL;
467                                                         seq->flag |= SEQ_RIGHTSEL;
468                                                 }
469                                                 break;
470                                         }
471                                 } else {
472                                         if(extend==0) deselect_all_seq(scene);
473                                         select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
474                                 }
475                         }
476                         recurs_sel_seq(seq);
477
478                         if(linked_time) {
479                                 select_linked_time(ed->seqbasep, seq);
480                         }
481                 }
482         }
483         
484         /* marker transform */
485 #if 0 // XXX probably need to redo this differently for 2.5
486         if (marker) {
487                 short mval[2], xo, yo;
488 //              getmouseco_areawin(mval);
489                 xo= mval[0]; 
490                 yo= mval[1];
491                 
492                 while(get_mbut()) {             
493 //                      getmouseco_areawin(mval);
494                         if(abs(mval[0]-xo)+abs(mval[1]-yo) > 4) {
495                                 transform_markers('g', 0);
496                                 return;
497                         }
498                 }
499         }
500 #endif
501         
502         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
503
504         /* allowing tweaks */
505         return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
506 }
507
508 void SEQUENCER_OT_select(wmOperatorType *ot)
509 {
510         /* identifiers */
511         ot->name= "Activate/Select";
512         ot->idname= "SEQUENCER_OT_select";
513         ot->description="Select a strip (last selected becomes the \"active strip\")";
514         
515         /* api callbacks */
516         ot->invoke= sequencer_select_invoke;
517         ot->poll= ED_operator_sequencer_active;
518         
519         /* flags */
520         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
521         
522         /* properties */
523         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection.");
524         RNA_def_boolean(ot->srna, "linked_handle", 0, "Linked Handle", "Select handles next to the active strip.");
525         /* for animation this is an enum but atm having an enum isnt useful for us */
526         RNA_def_boolean(ot->srna, "left_right", 0, "Left/Right", "select based on the frame side the cursor is on.");
527         RNA_def_boolean(ot->srna, "linked_time", 0, "Linked Time", "Select other strips at the same time.");
528 }
529
530
531
532
533 /* run recursivly to select linked */
534 static int select_more_less_seq__internal(Scene *scene, int sel, int linked) {
535         Editing *ed= seq_give_editing(scene, FALSE);
536         Sequence *seq, *neighbor;
537         int change=0;
538         int isel;
539         
540         if(ed==NULL) return 0;
541         
542         if (sel) {
543                 sel = SELECT;
544                 isel = 0;
545         } else {
546                 sel = 0;
547                 isel = SELECT;
548         }
549         
550         if (!linked) {
551                 /* if not linked we only want to touch each seq once, newseq */
552                 for(seq= ed->seqbasep->first; seq; seq= seq->next) {
553                         seq->tmp = NULL;
554                 }
555         }
556         
557         for(seq= ed->seqbasep->first; seq; seq= seq->next) {
558                 if((int)(seq->flag & SELECT) == sel) {
559                         if ((linked==0 && seq->tmp)==0) {
560                                 /* only get unselected nabours */
561                                 neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_LEFT, isel);
562                                 if (neighbor) {
563                                         if (sel) {neighbor->flag |= SELECT; recurs_sel_seq(neighbor);}
564                                         else            neighbor->flag &= ~SELECT;
565                                         if (linked==0) neighbor->tmp = (Sequence *)1;
566                                         change = 1;
567                                 }
568                                 neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_RIGHT, isel);
569                                 if (neighbor) {
570                                         if (sel) {neighbor->flag |= SELECT; recurs_sel_seq(neighbor);}
571                                         else            neighbor->flag &= ~SELECT;
572                                         if (linked==0) neighbor->tmp = (void *)1;
573                                         change = 1;
574                                 }
575                         }
576                 }
577         }
578         
579         return change;
580 }
581
582
583
584 /* select more operator */
585 static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
586 {
587         Scene *scene= CTX_data_scene(C);
588         
589         if(!select_more_less_seq__internal(scene, 0, 0))
590                 return OPERATOR_CANCELLED;
591
592         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
593         
594         return OPERATOR_FINISHED;
595 }
596
597 void SEQUENCER_OT_select_more(wmOperatorType *ot)
598 {
599         /* identifiers */
600         ot->name= "Select More";
601         ot->idname= "SEQUENCER_OT_select_more";
602         ot->description="Select more strips adjacent to the current selection";
603         
604         /* api callbacks */
605         ot->exec= sequencer_select_more_exec;
606         ot->poll= sequencer_edit_poll;
607         
608         /* flags */
609         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
610         
611         /* properties */
612 }
613
614
615 /* select less operator */
616 static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
617 {
618         Scene *scene= CTX_data_scene(C);
619         
620         if(!select_more_less_seq__internal(scene, 1, 0))
621                 return OPERATOR_CANCELLED;
622  
623         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
624         
625         return OPERATOR_FINISHED;
626 }
627
628 void SEQUENCER_OT_select_less(wmOperatorType *ot)
629 {
630         /* identifiers */
631         ot->name= "Select less";
632         ot->idname= "SEQUENCER_OT_select_less";
633         ot->description="Shrink the current selection of adjacent selected strips";
634         
635         /* api callbacks */
636         ot->exec= sequencer_select_less_exec;
637         ot->poll= sequencer_edit_poll;
638         
639         /* flags */
640         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
641         
642         /* properties */
643 }
644
645
646 /* select pick linked operator (uses the mouse) */
647 static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
648 {
649         Scene *scene= CTX_data_scene(C);
650         ARegion *ar= CTX_wm_region(C);
651         View2D *v2d= UI_view2d_fromcontext(C);
652         
653         short extend= RNA_boolean_get(op->ptr, "extend");
654         short mval[2];  
655         
656         Sequence *mouse_seq;
657         int selected, hand;
658         
659         mval[0]= event->x - ar->winrct.xmin;
660         mval[1]= event->y - ar->winrct.ymin;
661         
662         /* this works like UV, not mesh */
663         mouse_seq= find_nearest_seq(scene, v2d, &hand, mval);
664         if (!mouse_seq)
665                 return OPERATOR_FINISHED; /* user error as with mesh?? */
666         
667         if (extend==0)
668                 deselect_all_seq(scene);
669         
670         mouse_seq->flag |= SELECT;
671         recurs_sel_seq(mouse_seq);
672         
673         selected = 1;
674         while (selected) {
675                 selected = select_more_less_seq__internal(scene, 1, 1);
676         }
677         
678         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
679         
680         return OPERATOR_FINISHED;
681 }
682
683 void SEQUENCER_OT_select_linked_pick(wmOperatorType *ot)
684 {
685         /* identifiers */
686         ot->name= "Select pick linked";
687         ot->idname= "SEQUENCER_OT_select_linked_pick";
688         ot->description="Select a chain of linked strips nearest to the mouse pointer";
689         
690         /* api callbacks */
691         ot->invoke= sequencer_select_linked_pick_invoke;
692         ot->poll= ED_operator_sequencer_active;
693         
694         /* flags */
695         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
696         
697         /* properties */
698         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "extend the selection");
699 }
700
701
702 /* select linked operator */
703 static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
704 {
705         Scene *scene= CTX_data_scene(C);
706         int selected;
707
708         selected = 1;
709         while (selected) {
710                 selected = select_more_less_seq__internal(scene, 1, 1);
711         }
712
713         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
714
715         return OPERATOR_FINISHED;
716 }
717
718 void SEQUENCER_OT_select_linked(wmOperatorType *ot)
719 {
720         /* identifiers */
721         ot->name= "Select linked";
722         ot->idname= "SEQUENCER_OT_select_linked";
723         ot->description="Select all strips adjacent to the current selection";
724         
725         /* api callbacks */
726         ot->exec= sequencer_select_linked_exec;
727         ot->poll= sequencer_edit_poll;
728         
729         /* flags */
730         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
731         
732         /* properties */
733 }
734
735
736 /* select handles operator */
737 static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
738 {
739         Scene *scene= CTX_data_scene(C);
740         Editing *ed= seq_give_editing(scene, 0);
741         Sequence *seq;
742         int sel_side= RNA_enum_get(op->ptr, "side");
743
744
745         for(seq= ed->seqbasep->first; seq; seq=seq->next) {
746                 if (seq->flag & SELECT) {
747                         switch(sel_side) {
748                         case SEQ_SIDE_LEFT:
749                                 seq->flag &= ~SEQ_RIGHTSEL;
750                                 seq->flag |= SEQ_LEFTSEL;
751                                 break;
752                         case SEQ_SIDE_RIGHT:
753                                 seq->flag &= ~SEQ_LEFTSEL;
754                                 seq->flag |= SEQ_RIGHTSEL;
755                                 break;
756                         case SEQ_SIDE_BOTH:
757                                 seq->flag |= SEQ_LEFTSEL+SEQ_RIGHTSEL;
758                                 break;
759                         }
760                 }
761         }
762
763         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
764
765         return OPERATOR_FINISHED;
766 }
767
768 void SEQUENCER_OT_select_handles(wmOperatorType *ot)
769 {
770         /* identifiers */
771         ot->name= "Select Handles";
772         ot->idname= "SEQUENCER_OT_select_handles";
773         ot->description="Select manipulator handles on the sides of the selected strip";
774         
775         /* api callbacks */
776         ot->exec= sequencer_select_handles_exec;
777         ot->poll= sequencer_edit_poll;
778         
779         /* flags */
780         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
781         
782         /* properties */
783         RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side of the handle that is selected");
784 }
785
786 /* select side operator */
787 static int sequencer_select_active_side_exec(bContext *C, wmOperator *op)
788 {
789         Scene *scene= CTX_data_scene(C);
790         Editing *ed= seq_give_editing(scene, 0);
791         Sequence *seq_act= seq_active_get(scene);
792
793         if (ed==NULL || seq_act==NULL)
794                 return OPERATOR_CANCELLED;
795
796         seq_act->flag |= SELECT;
797
798         select_active_side(ed->seqbasep, RNA_enum_get(op->ptr, "side"), seq_act->machine, seq_act->startdisp);
799
800         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
801
802         return OPERATOR_FINISHED;
803 }
804
805 void SEQUENCER_OT_select_active_side(wmOperatorType *ot)
806 {
807         /* identifiers */
808         ot->name= "Select Active Side";
809         ot->idname= "SEQUENCER_OT_select_active_side";
810         ot->description="Select strips on the nominated side of the active strip";
811         
812         /* api callbacks */
813         ot->exec= sequencer_select_active_side_exec;
814         ot->poll= sequencer_edit_poll;
815
816         /* flags */
817         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
818
819         /* properties */
820         RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side of the handle that is selected");
821 }
822
823
824 /* borderselect operator */
825 static int sequencer_borderselect_exec(bContext *C, wmOperator *op)
826 {
827         Scene *scene= CTX_data_scene(C);
828         Editing *ed= seq_give_editing(scene, FALSE);
829         View2D *v2d= UI_view2d_fromcontext(C);
830         
831         Sequence *seq;
832         rcti rect;
833         rctf rectf, rq;
834         short selecting = (RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_SELECT);
835         short mval[2];
836
837         if(ed==NULL)
838                 return OPERATOR_CANCELLED;
839
840         rect.xmin= RNA_int_get(op->ptr, "xmin");
841         rect.ymin= RNA_int_get(op->ptr, "ymin");
842         rect.xmax= RNA_int_get(op->ptr, "xmax");
843         rect.ymax= RNA_int_get(op->ptr, "ymax");
844         
845         mval[0]= rect.xmin;
846         mval[1]= rect.ymin;
847         UI_view2d_region_to_view(v2d, mval[0], mval[1], &rectf.xmin, &rectf.ymin);
848         mval[0]= rect.xmax;
849         mval[1]= rect.ymax;
850         UI_view2d_region_to_view(v2d, mval[0], mval[1], &rectf.xmax, &rectf.ymax);
851
852         for(seq= ed->seqbasep->first; seq; seq= seq->next) {
853                 seq_rectf(seq, &rq);
854                 
855                 if(BLI_isect_rctf(&rq, &rectf, 0)) {
856                         if(selecting)           seq->flag |= SELECT;
857                         else                            seq->flag &= ~SEQ_ALLSEL;
858                         recurs_sel_seq(seq);
859                 }
860         }
861
862         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
863
864         return OPERATOR_FINISHED;
865
866
867
868 /* ****** Border Select ****** */
869 void SEQUENCER_OT_select_border(wmOperatorType *ot)
870 {
871         /* identifiers */
872         ot->name= "Border Select";
873         ot->idname= "SEQUENCER_OT_select_border";
874         ot->description="Enable border select mode";
875         
876         /* api callbacks */
877         ot->invoke= WM_border_select_invoke;
878         ot->exec= sequencer_borderselect_exec;
879         ot->modal= WM_border_select_modal;
880         
881         ot->poll= ED_operator_sequencer_active;
882         
883         /* flags */
884         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
885         
886         /* rna */
887         WM_operator_properties_gesture_border(ot, FALSE);
888 }