Cycles: svn merge -r36777:37040 https://svn.blender.org/svnroot/bf-blender/trunk...
[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         View2D *v2d= UI_view2d_fromcontext(C);
302         Scene *scene= CTX_data_scene(C);
303         Editing *ed= seq_give_editing(scene, FALSE);
304         short extend= RNA_boolean_get(op->ptr, "extend");
305         short linked_handle= RNA_boolean_get(op->ptr, "linked_handle");
306         short left_right= RNA_boolean_get(op->ptr, "left_right");
307         short linked_time= RNA_boolean_get(op->ptr, "linked_time");
308         
309         Sequence *seq,*neighbor, *act_orig;
310         int hand,sel_side;
311         TimeMarker *marker;
312
313         if(ed==NULL)
314                 return OPERATOR_CANCELLED;
315         
316         marker=find_nearest_marker(SCE_MARKERS, 1); //XXX - dummy function for now
317         
318         seq= find_nearest_seq(scene, v2d, &hand, event->mval);
319
320         // XXX - not nice, Ctrl+RMB needs to do left_right only when not over a strip
321         if(seq && linked_time && left_right)
322                 left_right= FALSE;
323
324
325         if (marker) {
326                 int oldflag;
327                 /* select timeline marker */
328                 if (extend) {
329                         oldflag= marker->flag;
330                         if (oldflag & SELECT)
331                                 marker->flag &= ~SELECT;
332                         else
333                                 marker->flag |= SELECT;
334                 }
335                 else {
336                         /* deselect_markers(0, 0); */ /* XXX, in 2.4x, seq selection used to deselect all, need to re-thnik this for 2.5 */
337                         marker->flag |= SELECT;                         
338                 }
339                 
340         } else if (left_right) {
341                 /* use different logic for this */
342                 float x;
343                 deselect_all_seq(scene);
344                 UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, NULL);
345
346                 SEQP_BEGIN(ed, seq) {
347                         if (x < CFRA) {
348                                 if(seq->enddisp < CFRA) {
349                                         seq->flag |= SELECT;
350                                         recurs_sel_seq(seq);
351                                 }
352                         }
353                         else {
354                                 if(seq->startdisp > CFRA) {
355                                         seq->flag |= SELECT;
356                                         recurs_sel_seq(seq);
357                                 }
358                         }
359                 }
360                 SEQ_END
361                 
362                 {
363                         SpaceSeq *sseq= CTX_wm_space_seq(C);
364                         if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
365                                 TimeMarker *tmarker;
366
367                                 for (tmarker= scene->markers.first; tmarker; tmarker= tmarker->next) {
368                                         if(     ((x < CFRA) && tmarker->frame < CFRA) ||
369                                                 ((x >= CFRA) && tmarker->frame >= CFRA)
370                                         ) {
371                                                 tmarker->flag |= SELECT;
372                                         }
373                                         else {
374                                                 tmarker->flag &= ~SELECT;
375                                         }
376                                 }
377                         }
378                 }
379         } else {
380                 // seq= find_nearest_seq(scene, v2d, &hand, mval);
381
382                 act_orig= ed->act_seq;
383
384                 if(extend == 0 && linked_handle==0)
385                         deselect_all_seq(scene);
386         
387                 if(seq) {
388                         seq_active_set(scene, seq);
389         
390                         if ((seq->type == SEQ_IMAGE) || (seq->type == SEQ_MOVIE)) {
391                                 if(seq->strip) {
392                                         strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR-1);
393                                 }
394                         } else
395                         if (seq->type == SEQ_SOUND) {
396                                 if(seq->strip) {
397                                         strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR-1);
398                                 }
399                         }
400         
401                         if(extend && (seq->flag & SELECT) && ed->act_seq == act_orig ) {
402                                 switch(hand) {
403                                 case SEQ_SIDE_NONE:
404                                         if (linked_handle==0)
405                                                 seq->flag &= ~SEQ_ALLSEL;
406                                         break;
407                                 case SEQ_SIDE_LEFT:
408                                         seq->flag ^= SEQ_LEFTSEL;
409                                         break;
410                                 case SEQ_SIDE_RIGHT:
411                                         seq->flag ^= SEQ_RIGHTSEL;
412                                         break;
413                                 }
414                         }
415                         else {
416                                 seq->flag |= SELECT;
417                                 if(hand==SEQ_SIDE_LEFT)         seq->flag |= SEQ_LEFTSEL;
418                                 if(hand==SEQ_SIDE_RIGHT)        seq->flag |= SEQ_RIGHTSEL;
419                         }
420                         
421                         /* On Alt selection, select the strip and bordering handles */
422                         if (linked_handle && !ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
423                                 if(extend==0) deselect_all_seq(scene);
424                                 seq->flag |= SELECT;
425                                 select_surrounding_handles(scene, seq);
426                         }
427                         else if (linked_handle && ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT) && (seq->flag & SELECT)) {
428                                 /*
429                                  * First click selects adjacent handles on that side.
430                                  * Second click selects all strips in that direction.
431                                  * If there are no adjacent strips, it just selects all in that direction.
432                                  */
433                                 sel_side= hand;
434                                 neighbor=find_neighboring_sequence(scene, seq, sel_side, -1);
435                                 if (neighbor) {
436                                         switch (sel_side) {
437                                         case SEQ_SIDE_LEFT:
438                                                 if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
439                                                         if(extend==0) deselect_all_seq(scene);
440                                                         seq->flag |= SELECT;
441                                                         
442                                                         select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
443                                                 } else {
444                                                         if(extend==0) deselect_all_seq(scene);
445                                                         seq->flag |= SELECT;
446
447                                                         neighbor->flag |= SELECT;
448                                                         recurs_sel_seq(neighbor);
449                                                         neighbor->flag |= SEQ_RIGHTSEL;
450                                                         seq->flag |= SEQ_LEFTSEL;
451                                                 }
452                                                 break;
453                                         case SEQ_SIDE_RIGHT:
454                                                 if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
455                                                         if(extend==0) deselect_all_seq(scene);
456                                                         seq->flag |= SELECT;
457
458                                                         select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
459                                                 } else {
460                                                         if(extend==0) deselect_all_seq(scene);
461                                                         seq->flag |= SELECT;
462
463                                                         neighbor->flag |= SELECT;
464                                                         recurs_sel_seq(neighbor);
465                                                         neighbor->flag |= SEQ_LEFTSEL;
466                                                         seq->flag |= SEQ_RIGHTSEL;
467                                                 }
468                                                 break;
469                                         }
470                                 } else {
471                                         if(extend==0) deselect_all_seq(scene);
472                                         select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
473                                 }
474                         }
475                         recurs_sel_seq(seq);
476
477                         if(linked_time) {
478                                 select_linked_time(ed->seqbasep, seq);
479                         }
480                 }
481         }
482         
483         /* marker transform */
484 #if 0 // XXX probably need to redo this differently for 2.5
485         if (marker) {
486                 int mval[2], xo, yo;
487 //              getmouseco_areawin(mval);
488                 xo= mval[0]; 
489                 yo= mval[1];
490                 
491                 while(get_mbut()) {             
492 //                      getmouseco_areawin(mval);
493                         if(abs(mval[0]-xo)+abs(mval[1]-yo) > 4) {
494                                 transform_markers('g', 0);
495                                 return;
496                         }
497                 }
498         }
499 #endif
500         
501         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
502
503         /* allowing tweaks */
504         return OPERATOR_FINISHED|OPERATOR_PASS_THROUGH;
505 }
506
507 void SEQUENCER_OT_select(wmOperatorType *ot)
508 {
509         /* identifiers */
510         ot->name= "Activate/Select";
511         ot->idname= "SEQUENCER_OT_select";
512         ot->description="Select a strip (last selected becomes the \"active strip\")";
513         
514         /* api callbacks */
515         ot->invoke= sequencer_select_invoke;
516         ot->poll= ED_operator_sequencer_active;
517         
518         /* flags */
519         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
520         
521         /* properties */
522         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection.");
523         RNA_def_boolean(ot->srna, "linked_handle", 0, "Linked Handle", "Select handles next to the active strip.");
524         /* for animation this is an enum but atm having an enum isnt useful for us */
525         RNA_def_boolean(ot->srna, "left_right", 0, "Left/Right", "select based on the frame side the cursor is on.");
526         RNA_def_boolean(ot->srna, "linked_time", 0, "Linked Time", "Select other strips at the same time.");
527 }
528
529
530
531
532 /* run recursivly to select linked */
533 static int select_more_less_seq__internal(Scene *scene, int sel, int linked) {
534         Editing *ed= seq_give_editing(scene, FALSE);
535         Sequence *seq, *neighbor;
536         int change=0;
537         int isel;
538         
539         if(ed==NULL) return 0;
540         
541         if (sel) {
542                 sel = SELECT;
543                 isel = 0;
544         } else {
545                 sel = 0;
546                 isel = SELECT;
547         }
548         
549         if (!linked) {
550                 /* if not linked we only want to touch each seq once, newseq */
551                 for(seq= ed->seqbasep->first; seq; seq= seq->next) {
552                         seq->tmp = NULL;
553                 }
554         }
555         
556         for(seq= ed->seqbasep->first; seq; seq= seq->next) {
557                 if((int)(seq->flag & SELECT) == sel) {
558                         if ((linked==0 && seq->tmp)==0) {
559                                 /* only get unselected nabours */
560                                 neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_LEFT, isel);
561                                 if (neighbor) {
562                                         if (sel) {neighbor->flag |= SELECT; recurs_sel_seq(neighbor);}
563                                         else            neighbor->flag &= ~SELECT;
564                                         if (linked==0) neighbor->tmp = (Sequence *)1;
565                                         change = 1;
566                                 }
567                                 neighbor = find_neighboring_sequence(scene, seq, SEQ_SIDE_RIGHT, 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 = (void *)1;
572                                         change = 1;
573                                 }
574                         }
575                 }
576         }
577         
578         return change;
579 }
580
581
582
583 /* select more operator */
584 static int sequencer_select_more_exec(bContext *C, wmOperator *UNUSED(op))
585 {
586         Scene *scene= CTX_data_scene(C);
587         
588         if(!select_more_less_seq__internal(scene, 0, 0))
589                 return OPERATOR_CANCELLED;
590
591         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
592         
593         return OPERATOR_FINISHED;
594 }
595
596 void SEQUENCER_OT_select_more(wmOperatorType *ot)
597 {
598         /* identifiers */
599         ot->name= "Select More";
600         ot->idname= "SEQUENCER_OT_select_more";
601         ot->description="Select more strips adjacent to the current selection";
602         
603         /* api callbacks */
604         ot->exec= sequencer_select_more_exec;
605         ot->poll= sequencer_edit_poll;
606         
607         /* flags */
608         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
609         
610         /* properties */
611 }
612
613
614 /* select less operator */
615 static int sequencer_select_less_exec(bContext *C, wmOperator *UNUSED(op))
616 {
617         Scene *scene= CTX_data_scene(C);
618         
619         if(!select_more_less_seq__internal(scene, 1, 0))
620                 return OPERATOR_CANCELLED;
621  
622         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
623         
624         return OPERATOR_FINISHED;
625 }
626
627 void SEQUENCER_OT_select_less(wmOperatorType *ot)
628 {
629         /* identifiers */
630         ot->name= "Select less";
631         ot->idname= "SEQUENCER_OT_select_less";
632         ot->description="Shrink the current selection of adjacent selected strips";
633         
634         /* api callbacks */
635         ot->exec= sequencer_select_less_exec;
636         ot->poll= sequencer_edit_poll;
637         
638         /* flags */
639         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
640         
641         /* properties */
642 }
643
644
645 /* select pick linked operator (uses the mouse) */
646 static int sequencer_select_linked_pick_invoke(bContext *C, wmOperator *op, wmEvent *event)
647 {
648         Scene *scene= CTX_data_scene(C);
649         View2D *v2d= UI_view2d_fromcontext(C);
650         
651         short extend= RNA_boolean_get(op->ptr, "extend");
652         
653         Sequence *mouse_seq;
654         int selected, hand;
655
656         /* this works like UV, not mesh */
657         mouse_seq= find_nearest_seq(scene, v2d, &hand, event->mval);
658         if (!mouse_seq)
659                 return OPERATOR_FINISHED; /* user error as with mesh?? */
660         
661         if (extend==0)
662                 deselect_all_seq(scene);
663         
664         mouse_seq->flag |= SELECT;
665         recurs_sel_seq(mouse_seq);
666         
667         selected = 1;
668         while (selected) {
669                 selected = select_more_less_seq__internal(scene, 1, 1);
670         }
671         
672         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
673         
674         return OPERATOR_FINISHED;
675 }
676
677 void SEQUENCER_OT_select_linked_pick(wmOperatorType *ot)
678 {
679         /* identifiers */
680         ot->name= "Select pick linked";
681         ot->idname= "SEQUENCER_OT_select_linked_pick";
682         ot->description="Select a chain of linked strips nearest to the mouse pointer";
683         
684         /* api callbacks */
685         ot->invoke= sequencer_select_linked_pick_invoke;
686         ot->poll= ED_operator_sequencer_active;
687         
688         /* flags */
689         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
690         
691         /* properties */
692         RNA_def_boolean(ot->srna, "extend", 0, "Extend", "extend the selection");
693 }
694
695
696 /* select linked operator */
697 static int sequencer_select_linked_exec(bContext *C, wmOperator *UNUSED(op))
698 {
699         Scene *scene= CTX_data_scene(C);
700         int selected;
701
702         selected = 1;
703         while (selected) {
704                 selected = select_more_less_seq__internal(scene, 1, 1);
705         }
706
707         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
708
709         return OPERATOR_FINISHED;
710 }
711
712 void SEQUENCER_OT_select_linked(wmOperatorType *ot)
713 {
714         /* identifiers */
715         ot->name= "Select linked";
716         ot->idname= "SEQUENCER_OT_select_linked";
717         ot->description="Select all strips adjacent to the current selection";
718         
719         /* api callbacks */
720         ot->exec= sequencer_select_linked_exec;
721         ot->poll= sequencer_edit_poll;
722         
723         /* flags */
724         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
725         
726         /* properties */
727 }
728
729
730 /* select handles operator */
731 static int sequencer_select_handles_exec(bContext *C, wmOperator *op)
732 {
733         Scene *scene= CTX_data_scene(C);
734         Editing *ed= seq_give_editing(scene, 0);
735         Sequence *seq;
736         int sel_side= RNA_enum_get(op->ptr, "side");
737
738
739         for(seq= ed->seqbasep->first; seq; seq=seq->next) {
740                 if (seq->flag & SELECT) {
741                         switch(sel_side) {
742                         case SEQ_SIDE_LEFT:
743                                 seq->flag &= ~SEQ_RIGHTSEL;
744                                 seq->flag |= SEQ_LEFTSEL;
745                                 break;
746                         case SEQ_SIDE_RIGHT:
747                                 seq->flag &= ~SEQ_LEFTSEL;
748                                 seq->flag |= SEQ_RIGHTSEL;
749                                 break;
750                         case SEQ_SIDE_BOTH:
751                                 seq->flag |= SEQ_LEFTSEL+SEQ_RIGHTSEL;
752                                 break;
753                         }
754                 }
755         }
756
757         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
758
759         return OPERATOR_FINISHED;
760 }
761
762 void SEQUENCER_OT_select_handles(wmOperatorType *ot)
763 {
764         /* identifiers */
765         ot->name= "Select Handles";
766         ot->idname= "SEQUENCER_OT_select_handles";
767         ot->description="Select manipulator handles on the sides of the selected strip";
768         
769         /* api callbacks */
770         ot->exec= sequencer_select_handles_exec;
771         ot->poll= sequencer_edit_poll;
772         
773         /* flags */
774         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
775         
776         /* properties */
777         RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side of the handle that is selected");
778 }
779
780 /* select side operator */
781 static int sequencer_select_active_side_exec(bContext *C, wmOperator *op)
782 {
783         Scene *scene= CTX_data_scene(C);
784         Editing *ed= seq_give_editing(scene, 0);
785         Sequence *seq_act= seq_active_get(scene);
786
787         if (ed==NULL || seq_act==NULL)
788                 return OPERATOR_CANCELLED;
789
790         seq_act->flag |= SELECT;
791
792         select_active_side(ed->seqbasep, RNA_enum_get(op->ptr, "side"), seq_act->machine, seq_act->startdisp);
793
794         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
795
796         return OPERATOR_FINISHED;
797 }
798
799 void SEQUENCER_OT_select_active_side(wmOperatorType *ot)
800 {
801         /* identifiers */
802         ot->name= "Select Active Side";
803         ot->idname= "SEQUENCER_OT_select_active_side";
804         ot->description="Select strips on the nominated side of the active strip";
805         
806         /* api callbacks */
807         ot->exec= sequencer_select_active_side_exec;
808         ot->poll= sequencer_edit_poll;
809
810         /* flags */
811         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
812
813         /* properties */
814         RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side of the handle that is selected");
815 }
816
817
818 /* borderselect operator */
819 static int sequencer_borderselect_exec(bContext *C, wmOperator *op)
820 {
821         Scene *scene= CTX_data_scene(C);
822         Editing *ed= seq_give_editing(scene, FALSE);
823         View2D *v2d= UI_view2d_fromcontext(C);
824         
825         Sequence *seq;
826         rcti rect;
827         rctf rectf, rq;
828         short selecting = (RNA_int_get(op->ptr, "gesture_mode")==GESTURE_MODAL_SELECT);
829         int mval[2];
830
831         if(ed==NULL)
832                 return OPERATOR_CANCELLED;
833
834         rect.xmin= RNA_int_get(op->ptr, "xmin");
835         rect.ymin= RNA_int_get(op->ptr, "ymin");
836         rect.xmax= RNA_int_get(op->ptr, "xmax");
837         rect.ymax= RNA_int_get(op->ptr, "ymax");
838         
839         mval[0]= rect.xmin;
840         mval[1]= rect.ymin;
841         UI_view2d_region_to_view(v2d, mval[0], mval[1], &rectf.xmin, &rectf.ymin);
842         mval[0]= rect.xmax;
843         mval[1]= rect.ymax;
844         UI_view2d_region_to_view(v2d, mval[0], mval[1], &rectf.xmax, &rectf.ymax);
845
846         for(seq= ed->seqbasep->first; seq; seq= seq->next) {
847                 seq_rectf(seq, &rq);
848                 
849                 if(BLI_isect_rctf(&rq, &rectf, 0)) {
850                         if(selecting)           seq->flag |= SELECT;
851                         else                            seq->flag &= ~SEQ_ALLSEL;
852                         recurs_sel_seq(seq);
853                 }
854         }
855
856         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER|NA_SELECTED, scene);
857
858         return OPERATOR_FINISHED;
859
860
861
862 /* ****** Border Select ****** */
863 void SEQUENCER_OT_select_border(wmOperatorType *ot)
864 {
865         /* identifiers */
866         ot->name= "Border Select";
867         ot->idname= "SEQUENCER_OT_select_border";
868         ot->description="Enable border select mode";
869         
870         /* api callbacks */
871         ot->invoke= WM_border_select_invoke;
872         ot->exec= sequencer_borderselect_exec;
873         ot->modal= WM_border_select_modal;
874         
875         ot->poll= ED_operator_sequencer_active;
876         
877         /* flags */
878         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
879         
880         /* rna */
881         WM_operator_properties_gesture_border(ot, FALSE);
882 }