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