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