2.5: code consistency
[blender-staging.git] / source / blender / editors / space_sequencer / sequencer_edit.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
21  * All rights reserved.
22  *
23  * Contributor(s): Blender Foundation, 2003-2009
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include <stdlib.h>
29 #include <math.h>
30 #include <string.h>
31
32 #ifndef WIN32
33 #include <unistd.h>
34 #else
35 #include <io.h>
36 #endif
37 #include <sys/types.h>
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_arithb.h"
43 #include "BLI_storage_types.h"
44
45 #include "IMB_imbuf_types.h"
46 #include "IMB_imbuf.h"
47
48 #include "DNA_ipo_types.h"
49 #include "DNA_curve_types.h"
50 #include "DNA_scene_types.h"
51 #include "DNA_screen_types.h"
52 #include "DNA_space_types.h"
53 #include "DNA_sequence_types.h"
54 #include "DNA_view2d_types.h"
55 #include "DNA_userdef_types.h"
56 #include "DNA_sound_types.h"
57
58 #include "BKE_context.h"
59 #include "BKE_global.h"
60 #include "BKE_image.h"
61 #include "BKE_library.h"
62 #include "BKE_main.h"
63 #include "BKE_plugin_types.h"
64 #include "BKE_sequence.h"
65 #include "BKE_scene.h"
66 #include "BKE_utildefines.h"
67 #include "BKE_report.h"
68
69 #include "WM_api.h"
70 #include "WM_types.h"
71
72 #include "RNA_access.h"
73 #include "RNA_define.h"
74
75 /* for menu/popup icons etc etc*/
76 #include "UI_interface.h"
77 #include "UI_resources.h"
78
79 #include "ED_anim_api.h"
80 #include "ED_space_api.h"
81 #include "ED_types.h"
82 #include "ED_screen.h"
83 #include "ED_transform.h"
84 #include "ED_util.h"
85
86 #include "UI_interface.h"
87 #include "UI_resources.h"
88 #include "UI_view2d.h"
89
90 /* own include */
91 #include "sequencer_intern.h"
92
93 /* XXX */
94 //static Sequence *_last_seq=0;
95 //static int _last_seq_init=0;
96 /* XXX */
97 static void error() {}
98 static void waitcursor() {}
99 static void activate_fileselect() {}
100 static int pupmenu() {return 0;}
101 static int okee() {return 0;}
102
103
104 /* XXX */
105 /* RNA Enums, used in multiple files */
106 EnumPropertyItem sequencer_prop_effect_types[] = {
107         {SEQ_CROSS, "CROSS", 0, "Crossfade", "Crossfade effect strip type"},
108         {SEQ_ADD, "ADD", 0, "Add", "Add effect strip type"},
109         {SEQ_SUB, "SUBTRACT", 0, "Subtract", "Subtract effect strip type"},
110         {SEQ_ALPHAOVER, "ALPHA_OVER", 0, "Alpha Over", "Alpha Over effect strip type"},
111         {SEQ_ALPHAUNDER, "ALPHA_UNDER", 0, "Alpha Under", "Alpha Under effect strip type"},
112         {SEQ_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Cross", "Gamma Cross effect strip type"},
113         {SEQ_MUL, "MULTIPLY", 0, "Multiply", "Multiply effect strip type"},
114         {SEQ_OVERDROP, "OVER_DROP", 0, "Alpha Over Drop", "Alpha Over Drop effect strip type"},
115         {SEQ_PLUGIN, "PLUGIN", 0, "Plugin", "Plugin effect strip type"},
116         {SEQ_WIPE, "WIPE", 0, "Wipe", "Wipe effect strip type"},
117         {SEQ_GLOW, "GLOW", 0, "Glow", "Glow effect strip type"},
118         {SEQ_TRANSFORM, "TRANSFORM", 0, "Transform", "Transform effect strip type"},
119         {SEQ_COLOR, "COLOR", 0, "Color", "Color effect strip type"},
120         {SEQ_SPEED, "SPEED", 0, "Speed", "Color effect strip type"},
121         {0, NULL, 0, NULL, NULL}
122 };
123
124 /* mute operator */
125 EnumPropertyItem sequencer_prop_operate_types[] = { /* better name? */
126         {SEQ_SELECTED, "SELECTED", 0, "Selected", ""},
127         {SEQ_UNSELECTED, "UNSELECTED", 0, "Unselected ", ""},
128         {0, NULL, 0, NULL, NULL}
129 };
130
131  EnumPropertyItem prop_side_types[] = {
132         {SEQ_SIDE_LEFT, "LEFT", 0, "Left", ""},
133         {SEQ_SIDE_RIGHT, "RIGHT", 0, "Right", ""},
134         {SEQ_SIDE_BOTH, "BOTH", 0, "Both", ""},
135         {0, NULL, 0, NULL, NULL}
136 };
137
138 typedef struct TransSeq {
139         int start, machine;
140         int startstill, endstill;
141         int startdisp, enddisp;
142         int startofs, endofs;
143         int final_left, final_right;
144         int len;
145 } TransSeq;
146
147 Sequence *get_last_seq(Scene *scene)
148 {
149         Editing *ed= seq_give_editing(scene, FALSE);
150         if(ed==NULL) return NULL;
151         return ed->act_seq;
152 }
153
154 void set_last_seq(Scene *scene, Sequence *seq)
155 {
156         Editing *ed= seq_give_editing(scene, FALSE);
157         if(ed==NULL) return;
158         
159         ed->act_seq= seq;
160 }
161
162 Sequence *get_foreground_frame_seq(Scene *scene, int frame)
163 {
164         Editing *ed= seq_give_editing(scene, FALSE);
165         Sequence *seq, *best_seq=NULL;
166         int best_machine = -1;
167         
168         if(!ed) return NULL;
169         
170         for (seq=ed->seqbasep->first; seq; seq= seq->next) {
171                 if(seq->flag & SEQ_MUTE || seq->startdisp > frame || seq->enddisp <= frame)
172                         continue;
173                 /* only use elements you can see - not */
174                 if (ELEM6(seq->type, SEQ_IMAGE, SEQ_META, SEQ_SCENE, SEQ_MOVIE, SEQ_MOVIE_AND_HD_SOUND, SEQ_COLOR)) {
175                         if (seq->machine > best_machine) {
176                                 best_seq = seq;
177                                 best_machine = seq->machine;
178                         }
179                 }
180         }
181         return best_seq;
182 }
183
184 void seq_rectf(Sequence *seq, rctf *rectf)
185 {
186         if(seq->startstill) rectf->xmin= seq->start;
187         else rectf->xmin= seq->startdisp;
188         rectf->ymin= seq->machine+SEQ_STRIP_OFSBOTTOM;
189         if(seq->endstill) rectf->xmax= seq->start+seq->len;
190         else rectf->xmax= seq->enddisp;
191         rectf->ymax= seq->machine+SEQ_STRIP_OFSTOP;
192 }
193
194 static void change_plugin_seq(Scene *scene, char *str)  /* called from fileselect */
195 {
196         Editing *ed= seq_give_editing(scene, FALSE);
197         struct SeqEffectHandle sh;
198         Sequence *last_seq= get_last_seq(scene);
199
200         if(last_seq && last_seq->type != SEQ_PLUGIN) return;
201
202         sh = get_sequence_effect(last_seq);
203         sh.free(last_seq);
204         sh.init_plugin(last_seq, str);
205
206         last_seq->machine = MAX3(last_seq->seq1->machine, 
207                                  last_seq->seq2->machine, 
208                                  last_seq->seq3->machine);
209
210         if( seq_test_overlap(ed->seqbasep, last_seq) ) shuffle_seq(ed->seqbasep, last_seq);
211         
212 }
213
214
215 void boundbox_seq(Scene *scene, rctf *rect)
216 {
217         Sequence *seq;
218         Editing *ed= seq_give_editing(scene, FALSE);
219         float min[2], max[2];
220
221         
222         if(ed==NULL) return;
223
224         min[0]= 0.0;
225         max[0]= EFRA+1;
226         min[1]= 0.0;
227         max[1]= 8.0;
228
229         seq= ed->seqbasep->first;
230         while(seq) {
231
232                 if( min[0] > seq->startdisp-1) min[0]= seq->startdisp-1;
233                 if( max[0] < seq->enddisp+1) max[0]= seq->enddisp+1;
234                 if( max[1] < seq->machine+2.0) max[1]= seq->machine+2.0;
235
236                 seq= seq->next;
237         }
238
239         rect->xmin= min[0];
240         rect->xmax= max[0];
241         rect->ymin= min[1];
242         rect->ymax= max[1];
243
244 }
245
246 int mouse_frame_side(View2D *v2d, short mouse_x, int frame ) 
247 {
248         short mval[2];
249         float mouseloc[2];
250         
251         mval[0]= mouse_x;
252         mval[1]= 0;
253         
254         /* choose the side based on which side of the playhead the mouse is on */
255         UI_view2d_region_to_view(v2d, mval[0], mval[1], &mouseloc[0], &mouseloc[1]);
256         
257         return mouseloc[0] > frame ? SEQ_SIDE_RIGHT : SEQ_SIDE_LEFT;
258 }
259
260
261 Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int sel) 
262 {
263         /* sel - 0==unselected, 1==selected, -1==done care*/
264         Sequence *seq;
265         Editing *ed= seq_give_editing(scene, FALSE);
266
267         if(ed==NULL) return NULL;
268
269         if (sel>0) sel = SELECT;
270         
271         for(seq= ed->seqbasep->first; seq; seq= seq->next) {
272                 if(     (seq!=test) &&
273                         (test->machine==seq->machine) &&
274                         ((sel == -1) || (sel && (seq->flag & SELECT)) || (sel==0 && (seq->flag & SELECT)==0)  ))
275                 {
276                         switch (lr) {
277                         case SEQ_SIDE_LEFT:
278                                 if (test->startdisp == (seq->enddisp)) {
279                                         return seq;
280                                 }
281                                 break;
282                         case SEQ_SIDE_RIGHT:
283                                 if (test->enddisp == (seq->startdisp)) {
284                                         return seq;
285                                 }
286                                 break;
287                         }
288                 }
289         }
290         return NULL;
291 }
292
293 Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, int sel) 
294 {
295         /* sel - 0==unselected, 1==selected, -1==done care*/
296         Sequence *seq,*best_seq = NULL;
297         Editing *ed= seq_give_editing(scene, FALSE);
298         
299         int dist, best_dist;
300         best_dist = MAXFRAME*2;
301
302         
303         if(ed==NULL) return NULL;
304
305         if (sel) sel = SELECT;
306         
307         seq= ed->seqbasep->first;
308         while(seq) {
309                 if(             (seq!=test) &&
310                                 (test->machine==seq->machine) &&
311                                 (test->depth==seq->depth) &&
312                                 ((sel == -1) || (sel==(seq->flag & SELECT))))
313                 {
314                         dist = MAXFRAME*2;
315                         
316                         switch (lr) {
317                         case SEQ_SIDE_LEFT:
318                                 if (seq->enddisp <= test->startdisp) {
319                                         dist = test->enddisp - seq->startdisp;
320                                 }
321                                 break;
322                         case SEQ_SIDE_RIGHT:
323                                 if (seq->startdisp >= test->enddisp) {
324                                         dist = seq->startdisp - test->enddisp;
325                                 }
326                                 break;
327                         }
328                         
329                         if (dist==0) {
330                                 best_seq = seq;
331                                 break;
332                         } else if (dist < best_dist) {
333                                 best_dist = dist;
334                                 best_seq = seq;
335                         }
336                 }
337                 seq= seq->next;
338         }
339         return best_seq; /* can be null */
340 }
341
342
343 Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, short mval[2])
344 {
345         Sequence *seq;
346         Editing *ed= seq_give_editing(scene, FALSE);
347         float x, y;
348         float pixelx;
349         float handsize;
350         float displen;
351         *hand= SEQ_SIDE_NONE;
352
353         
354         if(ed==NULL) return NULL;
355         
356         pixelx = (v2d->cur.xmax - v2d->cur.xmin)/(v2d->mask.xmax - v2d->mask.xmin);
357
358         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
359         
360         seq= ed->seqbasep->first;
361         
362         while(seq) {
363                 if(seq->machine == (int)y) {
364                         /* check for both normal strips, and strips that have been flipped horizontally */
365                         if( ((seq->startdisp < seq->enddisp) && (seq->startdisp<=x && seq->enddisp>=x)) ||
366                                 ((seq->startdisp > seq->enddisp) && (seq->startdisp>=x && seq->enddisp<=x)) )
367                         {
368                                 if(seq_tx_test(seq)) {
369                                         
370                                         /* clamp handles to defined size in pixel space */
371                                         
372                                         handsize = seq->handsize;
373                                         displen = (float)abs(seq->startdisp - seq->enddisp);
374                                         
375                                         if (displen / pixelx > 16) { /* dont even try to grab the handles of small strips */
376                                                 /* Set the max value to handle to 1/3 of the total len when its less then 28.
377                                                 * This is important because otherwise selecting handles happens even when you click in the middle */
378                                                 
379                                                 if ((displen/3) < 30*pixelx) {
380                                                         handsize = displen/3;
381                                                 } else {
382                                                         CLAMP(handsize, 7*pixelx, 30*pixelx);
383                                                 }
384                                                 
385                                                 if( handsize+seq->startdisp >=x )
386                                                         *hand= SEQ_SIDE_LEFT;
387                                                 else if( -handsize+seq->enddisp <=x )
388                                                         *hand= SEQ_SIDE_RIGHT;
389                                         }
390                                 }
391                                 return seq;
392                         }
393                 }
394                 seq= seq->next;
395         }
396         return 0;
397 }
398
399 void update_seq_ipo_rect(Scene *scene, View2D *v2d, Sequence *seq)
400 {
401         float start;
402         float end;
403
404         if (!seq || !seq->ipo) {
405                 return;
406         }
407         start =  -5.0;
408         end   =  105.0;
409
410         
411         /* Adjust IPO window to sequence and 
412            avoid annoying snap-back to startframe 
413            when Lock Time is on */
414         if (0) { // XXX v2d->flag & V2D_VIEWLOCK) {
415                 if ((seq->flag & SEQ_IPO_FRAME_LOCKED) != 0) {
416                         start = -5.0 + seq->startdisp;
417                         end = 5.0 + seq->enddisp;
418                 } else {
419                         start = (float)scene->r.sfra - 0.1;
420                         end = scene->r.efra;
421                 }
422         }
423
424         seq->ipo->cur.xmin= start;
425         seq->ipo->cur.xmax= end;
426 }
427
428 void update_seq_icu_rects(Sequence * seq)
429 {
430         IpoCurve *icu= NULL;
431         struct SeqEffectHandle sh;
432
433         if (!seq || !seq->ipo) {
434                 return;
435         }
436
437         if(!(seq->type & SEQ_EFFECT)) {
438                 return;
439         }
440
441         sh = get_sequence_effect(seq);
442
443         for(icu= seq->ipo->curve.first; icu; icu= icu->next) {
444                 sh.store_icu_yrange(seq, icu->adrcode, &icu->ymin, &icu->ymax);
445         }
446 }
447
448
449 static int seq_is_parent(Sequence *par, Sequence *seq)
450 {
451         return ((par->seq1 == seq) || (par->seq2 == seq) || (par->seq3 == seq));
452 }
453
454 static int seq_is_predecessor(Sequence *pred, Sequence *seq)
455 {
456         if (!pred) return 0;
457         if(pred == seq) return 0;
458         else if(seq_is_parent(pred, seq)) return 1;
459         else if(pred->seq1 && seq_is_predecessor(pred->seq1, seq)) return 1;
460         else if(pred->seq2 && seq_is_predecessor(pred->seq2, seq)) return 1;
461         else if(pred->seq3 && seq_is_predecessor(pred->seq3, seq)) return 1;
462
463         return 0;
464 }
465
466 void deselect_all_seq(Scene *scene)
467 {
468         Sequence *seq;
469         Editing *ed= seq_give_editing(scene, FALSE);
470
471         
472         if(ed==NULL) return;
473
474         SEQP_BEGIN(ed, seq) {
475                 seq->flag &= SEQ_DESEL;
476         }
477         SEQ_END
478                 
479 }
480
481 void recurs_sel_seq(Sequence *seqm)
482 {
483         Sequence *seq;
484
485         seq= seqm->seqbase.first;
486         while(seq) {
487
488                 if(seqm->flag & (SEQ_LEFTSEL+SEQ_RIGHTSEL)) seq->flag &= SEQ_DESEL;
489                 else if(seqm->flag & SELECT) seq->flag |= SELECT;
490                 else seq->flag &= SEQ_DESEL;
491
492                 if(seq->seqbase.first) recurs_sel_seq(seq);
493
494                 seq= seq->next;
495         }
496 }
497
498 Sequence *alloc_sequence(ListBase *lb, int cfra, int machine)
499 {
500         Sequence *seq;
501
502         /*ed= scene->ed;*/
503
504         seq= MEM_callocN( sizeof(Sequence), "addseq");
505         BLI_addtail(lb, seq);
506
507         //set_last_seq(scene, seq); // Probably not a great idea at such a low level anyway - Campbell
508
509         *( (short *)seq->name )= ID_SEQ;
510         seq->name[2]= 0;
511
512         seq->flag= SELECT;
513         seq->start= cfra;
514         seq->machine= machine;
515         seq->mul= 1.0;
516         seq->blend_opacity = 100.0;
517         
518         return seq;
519 }
520
521 int event_to_efftype(int event)
522 {
523         if(event==2) return SEQ_CROSS;
524         if(event==3) return SEQ_GAMCROSS;
525         if(event==4) return SEQ_ADD;
526         if(event==5) return SEQ_SUB;
527         if(event==6) return SEQ_MUL;
528         if(event==7) return SEQ_ALPHAOVER;
529         if(event==8) return SEQ_ALPHAUNDER;
530         if(event==9) return SEQ_OVERDROP;
531         if(event==10) return SEQ_PLUGIN;
532         if(event==13) return SEQ_WIPE;
533         if(event==14) return SEQ_GLOW;
534         if(event==15) return SEQ_TRANSFORM;
535         if(event==16) return SEQ_COLOR;
536         if(event==17) return SEQ_SPEED;
537         return 0;
538 }
539
540 #if 0
541 static void reload_sound_strip(Scene *scene, char *name)
542 {
543         Editing *ed;
544         Sequence *seq, *seqact;
545         SpaceFile *sfile;
546         Sequence *last_seq= get_last_seq(scene);
547
548         ed= scene->ed;
549
550         if(last_seq==0 || last_seq->type!=SEQ_SOUND) return;
551         seqact= last_seq;       /* last_seq changes in alloc_sequence */
552
553         /* search sfile */
554 //      sfile= scrarea_find_space_of_type(curarea, SPACE_FILE);
555         if(sfile==0) return;
556
557         waitcursor(1);
558
559         seq = sfile_to_snd_sequence(sfile, seqact->start, seqact->machine);
560         printf("seq->type: %i\n", seq->type);
561         if(seq && seq!=seqact) {
562                 /* i'm not sure about this one, seems to work without it -- sgefant */
563                 seq_free_strip(seqact->strip);
564
565                 seqact->strip= seq->strip;
566
567                 seqact->len= seq->len;
568                 calc_sequence(seqact);
569
570                 seq->strip= 0;
571                 seq_free_sequence(ed, seq);
572                 BLI_remlink(ed->seqbasep, seq);
573
574                 seq= ed->seqbasep->first;
575
576         }
577
578         waitcursor(0);
579
580 }
581 #endif
582
583 static void reload_image_strip(Scene *scene, char *name)
584 {
585         Editing *ed= seq_give_editing(scene, FALSE);
586         Sequence *seq=NULL, *seqact;
587         SpaceFile *sfile=NULL;
588         Sequence *last_seq= get_last_seq(scene);
589
590
591
592         if(last_seq==0 || last_seq->type!=SEQ_IMAGE) return;
593         seqact= last_seq;       /* last_seq changes in alloc_sequence */
594
595         /* search sfile */
596 //      sfile= scrarea_find_space_of_type(curarea, SPACE_FILE);
597         if(sfile==0) return;
598
599         waitcursor(1);
600
601 //      seq= sfile_to_sequence(scene, sfile, seqact->start, seqact->machine, 1); // XXX ADD BACK
602         if(seq && seq!=seqact) {
603                 seq_free_strip(seqact->strip);
604
605                 seqact->strip= seq->strip;
606
607                 seqact->len= seq->len;
608                 calc_sequence(seqact);
609
610                 seq->strip= 0;
611                 seq_free_sequence(ed, seq);
612                 BLI_remlink(ed->seqbasep, seq);
613
614                 update_changed_seq_and_deps(scene, seqact, 1, 1);
615         }
616         waitcursor(0);
617
618 }
619
620
621 void change_sequence(Scene *scene)
622 {
623         Editing *ed= seq_give_editing(scene, FALSE);
624         Sequence *last_seq= get_last_seq(scene);
625         Scene *sce;
626         short event;
627
628         if(last_seq==0) return;
629
630         if(last_seq->type & SEQ_EFFECT) {
631                 event = pupmenu("Change Effect%t"
632                                 "|Switch A <-> B %x1"
633                                 "|Switch B <-> C %x10"
634                                 "|Plugin%x11"
635                                 "|Recalculate%x12"
636                                 "|Cross%x2"
637                                 "|Gamma Cross%x3"
638                                 "|Add%x4"
639                                 "|Sub%x5"
640                                 "|Mul%x6"
641                                 "|Alpha Over%x7"
642                                 "|Alpha Under%x8"
643                                 "|Alpha Over Drop%x9"
644                                 "|Wipe%x13"
645                                 "|Glow%x14"
646                                 "|Transform%x15"
647                                 "|Color Generator%x16"
648                                 "|Speed Control%x17");
649                 if(event > 0) {
650                         if(event==1) {
651                                 SWAP(Sequence *,last_seq->seq1,last_seq->seq2);
652                         }
653                         else if(event==10) {
654                                 SWAP(Sequence *,last_seq->seq2,last_seq->seq3);
655                         }
656                         else if(event==11) {
657                                 activate_fileselect(
658                                         FILE_SPECIAL, "Select Plugin", 
659                                         U.plugseqdir, change_plugin_seq);
660                         }
661                         else if(event==12);     
662                                 /* recalculate: only new_stripdata */
663                         else {
664                                 /* free previous effect and init new effect */
665                                 struct SeqEffectHandle sh;
666
667                                 if (get_sequence_effect_num_inputs(
668                                             last_seq->type)
669                                     < get_sequence_effect_num_inputs(
670                                             event_to_efftype(event))) {
671                                         error("New effect needs more "
672                                               "input strips!");
673                                 } else {
674                                         sh = get_sequence_effect(last_seq);
675                                         sh.free(last_seq);
676                                         
677                                         last_seq->type 
678                                                 = event_to_efftype(event);
679                                         
680                                         sh = get_sequence_effect(last_seq);
681                                         sh.init(last_seq);
682                                 }
683                         }
684
685                         update_changed_seq_and_deps(scene, last_seq, 0, 1);
686                 }
687         }
688         else if(last_seq->type == SEQ_IMAGE) {
689                 if(okee("Change images")) {
690                         activate_fileselect(FILE_SPECIAL, 
691                                             "Select Images", 
692                                             ed->act_imagedir, 
693                                             reload_image_strip);
694                 }
695         }
696         else if(last_seq->type == SEQ_MOVIE) {
697                 ;
698         }
699         else if(last_seq->type == SEQ_SCENE) {
700                 event= pupmenu("Change Scene%t|Update Start and End");
701
702                 if(event==1) {
703                         sce= last_seq->scene;
704
705                         last_seq->len= sce->r.efra - sce->r.sfra + 1;
706                         last_seq->sfra= sce->r.sfra;
707                         
708                         /* bad code to change seq->len? update_changed_seq_and_deps() expects the strip->len to be OK */
709                         new_tstripdata(last_seq);
710                         
711                         update_changed_seq_and_deps(scene, last_seq, 1, 1);
712
713                 }
714         }
715
716 }
717
718 int seq_effect_find_selected(Scene *scene, Sequence *activeseq, int type, Sequence **selseq1, Sequence **selseq2, Sequence **selseq3, char **error_str)
719 {
720         Editing *ed = seq_give_editing(scene, FALSE);
721         Sequence *seq1= 0, *seq2= 0, *seq3= 0, *seq;
722         
723         *error_str= NULL;
724
725         if (!activeseq)
726                 seq2= get_last_seq(scene);
727
728         for(seq=ed->seqbasep->first; seq; seq=seq->next) {
729                 if(seq->flag & SELECT) {
730                         if (seq->type == SEQ_RAM_SOUND || seq->type == SEQ_HD_SOUND) {
731                                 *error_str= "Can't apply effects to audio sequence strips";
732                                 return 0;
733                         }
734                         if((seq != activeseq) && (seq != seq2)) {
735                                 if(seq2==0) seq2= seq;
736                                 else if(seq1==0) seq1= seq;
737                                 else if(seq3==0) seq3= seq;
738                                 else {
739                                                                         *error_str= "Can't apply effect to more than 3 sequence strips";
740                                                                         return 0;
741                                 }
742                         }
743                 }
744         }
745        
746         /* make sequence selection a little bit more intuitive
747            for 3 strips: the last-strip should be sequence3 */
748         if (seq3 != 0 && seq2 != 0) {
749                 Sequence *tmp = seq2;
750                 seq2 = seq3;
751                 seq3 = tmp;
752         }
753         
754
755         switch(get_sequence_effect_num_inputs(type)) {
756         case 0:
757                 *selseq1 = *selseq2 = *selseq3 = 0;
758                 return 1; /* succsess */
759         case 1:
760                 if(seq2==0)  {
761                         *error_str= "Need at least one selected sequence strip";
762                         return 0;
763                 }
764                 if(seq1==0) seq1= seq2;
765                 if(seq3==0) seq3= seq2;
766         case 2:
767                 if(seq1==0 || seq2==0) {
768                         *error_str= "Need 2 selected sequence strips";
769                         return 0;
770                 }
771                 if(seq3==0) seq3= seq2;
772         }
773         
774         if (seq1==NULL && seq2==NULL && seq3==NULL) {
775                 *error_str= "TODO: in what cases does this happen?";
776                 return 0;
777         }
778         
779         *selseq1= seq1;
780         *selseq2= seq2;
781         *selseq3= seq3;
782
783         return 1;
784 }
785
786 void reassign_inputs_seq_effect(Scene *scene)
787 {
788         Editing *ed= seq_give_editing(scene, FALSE);
789         Sequence *seq1, *seq2, *seq3, *last_seq = get_last_seq(scene);
790         char *error_msg;
791
792         if(last_seq==0 || !(last_seq->type & SEQ_EFFECT)) return;
793         if(ed==NULL) return;
794
795         if(!seq_effect_find_selected(scene, last_seq, last_seq->type, &seq1, &seq2, &seq3, &error_msg)) {
796                 //BKE_report(op->reports, RPT_ERROR, error_msg); // XXX operatorify
797                 return;
798         }
799         /* see reassigning would create a cycle */
800         if(     seq_is_predecessor(seq1, last_seq) ||
801                 seq_is_predecessor(seq2, last_seq) ||
802                 seq_is_predecessor(seq3, last_seq)
803         ) {
804                 //BKE_report(op->reports, RPT_ERROR, "Can't reassign inputs: no cycles allowed"); // XXX operatorify
805                 return;
806         }
807         
808         last_seq->seq1 = seq1;
809         last_seq->seq2 = seq2;
810         last_seq->seq3 = seq3;
811
812         update_changed_seq_and_deps(scene, last_seq, 1, 1);
813
814 }
815
816 static Sequence *del_seq_find_replace_recurs(Scene *scene, Sequence *seq)
817 {
818         Sequence *seq1, *seq2, *seq3;
819
820         /* try to find a replacement input sequence, and flag for later deletion if
821            no replacement can be found */
822
823         if(!seq)
824                 return NULL;
825         else if(!(seq->type & SEQ_EFFECT))
826                 return ((seq->flag & SELECT)? NULL: seq);
827         else if(!(seq->flag & SELECT)) {
828                 /* try to find replacement for effect inputs */
829                 seq1= del_seq_find_replace_recurs(scene, seq->seq1);
830                 seq2= del_seq_find_replace_recurs(scene, seq->seq2);
831                 seq3= del_seq_find_replace_recurs(scene, seq->seq3);
832
833                 if(seq1==seq->seq1 && seq2==seq->seq2 && seq3==seq->seq3);
834                 else if(seq1 || seq2 || seq3) {
835                         seq->seq1= (seq1)? seq1: (seq2)? seq2: seq3;
836                         seq->seq2= (seq2)? seq2: (seq1)? seq1: seq3;
837                         seq->seq3= (seq3)? seq3: (seq1)? seq1: seq2;
838
839                         update_changed_seq_and_deps(scene, seq, 1, 1);
840                 }
841                 else
842                         seq->flag |= SELECT; /* mark for delete */
843         }
844
845         if (seq->flag & SELECT) {
846                 if((seq1 = del_seq_find_replace_recurs(scene, seq->seq1))) return seq1;
847                 if((seq2 = del_seq_find_replace_recurs(scene, seq->seq2))) return seq2;
848                 if((seq3 = del_seq_find_replace_recurs(scene, seq->seq3))) return seq3;
849                 else return NULL;
850         }
851         else
852                 return seq;
853 }
854
855 static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short deleteall)
856 {
857         Editing *ed= seq_give_editing(scene, FALSE);
858         Sequence *seq, *seqn;
859         Sequence *last_seq = get_last_seq(scene);
860
861         seq= lb->first;
862         while(seq) {
863                 seqn= seq->next;
864                 if((seq->flag & flag) || deleteall) {
865                         if(seq->type==SEQ_RAM_SOUND && seq->sound) 
866                                 seq->sound->id.us--;
867
868                         BLI_remlink(lb, seq);
869                         if(seq==last_seq) set_last_seq(scene, NULL);
870                         if(seq->type==SEQ_META) recurs_del_seq_flag(scene, &seq->seqbase, flag, 1);
871                         if(seq->ipo) seq->ipo->id.us--;
872                         seq_free_sequence(ed, seq);
873                 }
874                 seq= seqn;
875         }
876 }
877
878 static Sequence *dupli_seq(Sequence *seq) 
879 {
880         Sequence *seqn = MEM_dupallocN(seq);
881         // XXX animato: ID *id;
882
883         seq->tmp = seqn;
884                 
885         seqn->strip= MEM_dupallocN(seq->strip);
886
887         // XXX animato
888 #if 0
889         if (seqn->ipo) {
890                 if (U.dupflag & USER_DUP_IPO) {
891                         id= (ID *)seqn->ipo;
892                         seqn->ipo= copy_ipo(seqn->ipo);
893                         /* we don't need to decrease the number
894                          * of the ipo because we never increase it,
895                          * for example, adduplicate need decrease
896                          * the number but only because copy_object
897                          * call id_us_plus for the ipo block and
898                          * single_ipo_users only work if id->us > 1.
899                          *
900                          * need call ipo_idnew here, for drivers ??
901                          * - Diego
902                          */
903                 }
904                 else
905                         seqn->ipo->id.us++;
906         }
907 #endif
908
909         seqn->strip->tstripdata = 0;
910         seqn->strip->tstripdata_startstill = 0;
911         seqn->strip->tstripdata_endstill = 0;
912         seqn->strip->ibuf_startstill = 0;
913         seqn->strip->ibuf_endstill = 0;
914
915         if (seq->strip->crop) {
916                 seqn->strip->crop = MEM_dupallocN(seq->strip->crop);
917         }
918
919         if (seq->strip->transform) {
920                 seqn->strip->transform = MEM_dupallocN(seq->strip->transform);
921         }
922
923         if (seq->strip->proxy) {
924                 seqn->strip->proxy = MEM_dupallocN(seq->strip->proxy);
925         }
926
927         if (seq->strip->color_balance) {
928                 seqn->strip->color_balance 
929                         = MEM_dupallocN(seq->strip->color_balance);
930         }
931         
932         if(seq->type==SEQ_META) {
933                 seqn->strip->stripdata = 0;
934
935                 seqn->seqbase.first= seqn->seqbase.last= 0;
936                 /* WATCH OUT!!! - This metastrip is not recursively duplicated here - do this after!!! */
937                 /* - recurs_dupli_seq(&seq->seqbase,&seqn->seqbase);*/
938         } else if(seq->type == SEQ_SCENE) {
939                 seqn->strip->stripdata = 0;
940         } else if(seq->type == SEQ_MOVIE) {
941                 seqn->strip->stripdata = 
942                                 MEM_dupallocN(seq->strip->stripdata);
943                 seqn->anim= 0;
944         } else if(seq->type == SEQ_RAM_SOUND) {
945                 seqn->strip->stripdata = 
946                                 MEM_dupallocN(seq->strip->stripdata);
947                 seqn->sound->id.us++;
948         } else if(seq->type == SEQ_HD_SOUND) {
949                 seqn->strip->stripdata = 
950                                 MEM_dupallocN(seq->strip->stripdata);
951                 seqn->hdaudio = 0;
952         } else if(seq->type == SEQ_IMAGE) {
953                 seqn->strip->stripdata = 
954                                 MEM_dupallocN(seq->strip->stripdata);
955         } else if(seq->type >= SEQ_EFFECT) {
956                 if(seq->seq1 && seq->seq1->tmp) seqn->seq1= seq->seq1->tmp;
957                 if(seq->seq2 && seq->seq2->tmp) seqn->seq2= seq->seq2->tmp;
958                 if(seq->seq3 && seq->seq3->tmp) seqn->seq3= seq->seq3->tmp;
959
960                 if (seq->type & SEQ_EFFECT) {
961                         struct SeqEffectHandle sh;
962                         sh = get_sequence_effect(seq);
963                         if(sh.copy)
964                                 sh.copy(seq, seqn);
965                 }
966
967                 seqn->strip->stripdata = 0;
968                 
969         } else {
970                 fprintf(stderr, "Aiiiiekkk! sequence type not "
971                                 "handled in duplicate!\nExpect a crash"
972                                                 " now...\n");
973         }
974         
975         return seqn;
976 }
977
978 static Sequence * deep_dupli_seq(Sequence * seq)
979 {
980         Sequence * seqn = dupli_seq(seq);
981         if (seq->type == SEQ_META) {
982                 Sequence * s;
983                 for(s= seq->seqbase.first; s; s = s->next) {
984                         Sequence * n = deep_dupli_seq(s);
985                         if (n) { 
986                                 BLI_addtail(&seqn->seqbase, n);
987                         }
988                 }
989         }
990         return seqn;
991 }
992
993
994 static void recurs_dupli_seq(Scene *scene, ListBase *old, ListBase *new)
995 {
996         Sequence *seq;
997         Sequence *seqn = 0;
998         Sequence *last_seq = get_last_seq(scene);
999
1000         for(seq= old->first; seq; seq= seq->next) {
1001                 seq->tmp= NULL;
1002                 if(seq->flag & SELECT) {
1003                         seqn = dupli_seq(seq);
1004                         if (seqn) { /*should never fail */
1005                                 seq->flag &= SEQ_DESEL;
1006                                 seqn->flag &= ~(SEQ_LEFTSEL+SEQ_RIGHTSEL+SEQ_LOCK);
1007
1008                                 BLI_addtail(new, seqn);
1009                                 if(seq->type==SEQ_META)
1010                                         recurs_dupli_seq(scene, &seq->seqbase,&seqn->seqbase);
1011                                 
1012                                 if (seq == last_seq) {
1013                                         set_last_seq(scene, seqn);
1014                                 }
1015                         }
1016                 }
1017         }
1018 }
1019
1020 static Sequence *cut_seq_hard(Scene *scene, Sequence * seq, int cutframe)
1021 {
1022         TransSeq ts;
1023         Sequence *seqn = 0;
1024         int skip_dup = FALSE;
1025
1026         /* backup values */
1027         ts.start= seq->start;
1028         ts.machine= seq->machine;
1029         ts.startstill= seq->startstill;
1030         ts.endstill= seq->endstill;
1031         ts.startdisp= seq->startdisp;
1032         ts.enddisp= seq->enddisp;
1033         ts.startofs= seq->anim_startofs;
1034         ts.endofs= seq->anim_endofs;
1035         ts.len= seq->len;
1036         
1037         /* First Strip! */
1038         /* strips with extended stillfames before */
1039         
1040         if ((seq->startstill) && (cutframe <seq->start)) {
1041                 /* don't do funny things with METAs ... */
1042                 if (seq->type == SEQ_META) {
1043                         skip_dup = TRUE;
1044                         seq->startstill = seq->start - cutframe;
1045                 } else {
1046                         seq->start= cutframe -1;
1047                         seq->startstill= cutframe -seq->startdisp -1;
1048                         seq->anim_endofs += seq->len - 1;
1049                         seq->endstill= 0;
1050                 }
1051         }
1052         /* normal strip */
1053         else if ((cutframe >=seq->start)&&(cutframe <=(seq->start+seq->len))) {
1054                 seq->endofs = 0;
1055                 seq->endstill = 0;
1056                 seq->anim_endofs += (seq->start+seq->len) - cutframe;
1057         }
1058         /* strips with extended stillframes after */
1059         else if (((seq->start+seq->len) < cutframe) && (seq->endstill)) {
1060                 seq->endstill -= seq->enddisp - cutframe;
1061                 /* don't do funny things with METAs ... */
1062                 if (seq->type == SEQ_META) {
1063                         skip_dup = TRUE;
1064                 }
1065         }
1066         
1067         reload_sequence_new_file(scene, seq);
1068         calc_sequence(seq);
1069         
1070         if (!skip_dup) {
1071                 /* Duplicate AFTER the first change */
1072                 seqn = deep_dupli_seq(seq);
1073         }
1074         
1075         if (seqn) { 
1076                 seqn->flag |= SELECT;
1077                         
1078                 /* Second Strip! */
1079                 /* strips with extended stillframes before */
1080                 if ((seqn->startstill) && (cutframe == seqn->start + 1)) {
1081                         seqn->start = ts.start;
1082                         seqn->startstill= ts.start- cutframe;
1083                         seqn->anim_endofs = ts.endofs;
1084                         seqn->endstill = ts.endstill;
1085                 }
1086                 
1087                 /* normal strip */
1088                 else if ((cutframe>=seqn->start)&&(cutframe<=(seqn->start+seqn->len))) {
1089                         seqn->start = cutframe;
1090                         seqn->startstill = 0;
1091                         seqn->startofs = 0;
1092                         seqn->anim_startofs += cutframe - ts.start;
1093                         seqn->anim_endofs = ts.endofs;
1094                         seqn->endstill = ts.endstill;
1095                 }                               
1096                 
1097                 /* strips with extended stillframes after */
1098                 else if (((seqn->start+seqn->len) < cutframe) && (seqn->endstill)) {
1099                         seqn->start = cutframe;
1100                         seqn->startofs = 0;
1101                         seqn->anim_startofs += ts.len-1;
1102                         seqn->endstill = ts.enddisp - cutframe -1;
1103                         seqn->startstill = 0;
1104                 }
1105                 
1106                 reload_sequence_new_file(scene, seqn);
1107                 calc_sequence(seqn);
1108         }
1109         return seqn;
1110 }
1111
1112 static Sequence *cut_seq_soft(Scene *scene, Sequence * seq, int cutframe)
1113 {
1114         TransSeq ts;
1115         Sequence *seqn = 0;
1116         int skip_dup = FALSE;
1117
1118         /* backup values */
1119         ts.start= seq->start;
1120         ts.machine= seq->machine;
1121         ts.startstill= seq->startstill;
1122         ts.endstill= seq->endstill;
1123         ts.startdisp= seq->startdisp;
1124         ts.enddisp= seq->enddisp;
1125         ts.startofs= seq->startofs;
1126         ts.endofs= seq->endofs;
1127         ts.len= seq->len;
1128         
1129         /* First Strip! */
1130         /* strips with extended stillfames before */
1131         
1132         if ((seq->startstill) && (cutframe <seq->start)) {
1133                 /* don't do funny things with METAs ... */
1134                 if (seq->type == SEQ_META) {
1135                         skip_dup = TRUE;
1136                         seq->startstill = seq->start - cutframe;
1137                 } else {
1138                         seq->start= cutframe -1;
1139                         seq->startstill= cutframe -seq->startdisp -1;
1140                         seq->endofs = seq->len - 1;
1141                         seq->endstill= 0;
1142                 }
1143         }
1144         /* normal strip */
1145         else if ((cutframe >=seq->start)&&(cutframe <=(seq->start+seq->len))) {
1146                 seq->endofs = (seq->start+seq->len) - cutframe;
1147         }
1148         /* strips with extended stillframes after */
1149         else if (((seq->start+seq->len) < cutframe) && (seq->endstill)) {
1150                 seq->endstill -= seq->enddisp - cutframe;
1151                 /* don't do funny things with METAs ... */
1152                 if (seq->type == SEQ_META) {
1153                         skip_dup = TRUE;
1154                 }
1155         }
1156         
1157         calc_sequence(seq);
1158         
1159         if (!skip_dup) {
1160                 /* Duplicate AFTER the first change */
1161                 seqn = deep_dupli_seq(seq);
1162         }
1163         
1164         if (seqn) { 
1165                 seqn->flag |= SELECT;
1166                         
1167                 /* Second Strip! */
1168                 /* strips with extended stillframes before */
1169                 if ((seqn->startstill) && (cutframe == seqn->start + 1)) {
1170                         seqn->start = ts.start;
1171                         seqn->startstill= ts.start- cutframe;
1172                         seqn->endofs = ts.endofs;
1173                         seqn->endstill = ts.endstill;
1174                 }
1175                 
1176                 /* normal strip */
1177                 else if ((cutframe>=seqn->start)&&(cutframe<=(seqn->start+seqn->len))) {
1178                         seqn->startstill = 0;
1179                         seqn->startofs = cutframe - ts.start;
1180                         seqn->endofs = ts.endofs;
1181                         seqn->endstill = ts.endstill;
1182                 }                               
1183                 
1184                 /* strips with extended stillframes after */
1185                 else if (((seqn->start+seqn->len) < cutframe) && (seqn->endstill)) {
1186                         seqn->start = cutframe - ts.len +1;
1187                         seqn->startofs = ts.len-1;
1188                         seqn->endstill = ts.enddisp - cutframe -1;
1189                         seqn->startstill = 0;
1190                 }
1191                 
1192                 calc_sequence(seqn);
1193         }
1194         return seqn;
1195 }
1196
1197
1198 /* like duplicate, but only duplicate and cut overlapping strips,
1199  * strips to the left of the cutframe are ignored and strips to the right are moved into the new list */
1200 static int cut_seq_list(Scene *scene, ListBase *old, ListBase *new, int cutframe,
1201                         Sequence * (*cut_seq)(Scene *, Sequence *, int))
1202 {
1203         int did_something = FALSE;
1204         Sequence *seq, *seq_next;
1205         
1206         seq= old->first;
1207         
1208         while(seq) {
1209                 seq_next = seq->next; /* we need this because we may remove seq */
1210                 
1211                 seq->tmp= NULL;
1212                 if(seq->flag & SELECT) {
1213                         if(cutframe > seq->startdisp && 
1214                            cutframe < seq->enddisp) {
1215                                 Sequence * seqn = cut_seq(scene, seq, cutframe);
1216                                 if (seqn) {
1217                                         BLI_addtail(new, seqn);
1218                                 }
1219                                 did_something = TRUE;
1220                         } else if (seq->enddisp <= cutframe) {
1221                                 /* do nothing */
1222                         } else if (seq->startdisp >= cutframe) {
1223                                 /* move into new list */
1224                                 BLI_remlink(old, seq);
1225                                 BLI_addtail(new, seq);
1226                         }
1227                 }
1228                 seq = seq_next;
1229         }
1230         return did_something;
1231 }
1232
1233 int insert_gap(Scene *scene, int gap, int cfra)
1234 {
1235         Sequence *seq;
1236         Editing *ed= seq_give_editing(scene, FALSE);
1237         int done=0;
1238
1239         /* all strips >= cfra are shifted */
1240         
1241         if(ed==NULL) return 0;
1242
1243         SEQP_BEGIN(ed, seq) {
1244                 if(seq->startdisp >= cfra) {
1245                         seq->start+= gap;
1246                         calc_sequence(seq);
1247                         done= 1;
1248                 }
1249         }
1250         SEQ_END
1251
1252         return done;
1253 }
1254
1255 void touch_seq_files(Scene *scene)
1256 {
1257         Sequence *seq;
1258         Editing *ed= seq_give_editing(scene, FALSE);
1259         char str[256];
1260
1261         /* touch all strips with movies */
1262         
1263         if(ed==NULL) return;
1264
1265         if(okee("Touch and print selected movies")==0) return;
1266
1267         waitcursor(1);
1268
1269         SEQP_BEGIN(ed, seq) {
1270                 if(seq->flag & SELECT) {
1271                         if(seq->type==SEQ_MOVIE) {
1272                                 if(seq->strip && seq->strip->stripdata) {
1273                                         BLI_make_file_string(G.sce, str, seq->strip->dir, seq->strip->stripdata->name);
1274                                         BLI_touch(seq->name);
1275                                 }
1276                         }
1277
1278                 }
1279         }
1280         SEQ_END
1281
1282         waitcursor(0);
1283 }
1284
1285 void set_filter_seq(Scene *scene)
1286 {
1287         Sequence *seq;
1288         Editing *ed= seq_give_editing(scene, FALSE);
1289
1290         
1291         if(ed==NULL) return;
1292
1293         if(okee("Set Deinterlace")==0) return;
1294
1295         SEQP_BEGIN(ed, seq) {
1296                 if(seq->flag & SELECT) {
1297                         if(seq->type==SEQ_MOVIE) {
1298                                 seq->flag |= SEQ_FILTERY;
1299                                 reload_sequence_new_file(scene, seq);
1300                         }
1301
1302                 }
1303         }
1304         SEQ_END
1305
1306 }
1307
1308 void seq_remap_paths(Scene *scene)
1309 {
1310         Sequence *seq, *last_seq = get_last_seq(scene);
1311         Editing *ed= seq_give_editing(scene, FALSE);
1312         char from[FILE_MAX], to[FILE_MAX], stripped[FILE_MAX];
1313         
1314         
1315         if(last_seq==NULL) 
1316                 return;
1317         
1318         BLI_strncpy(from, last_seq->strip->dir, FILE_MAX);
1319 // XXX  if (0==sbutton(from, 0, sizeof(from)-1, "From: "))
1320 //              return;
1321         
1322         strcpy(to, from);
1323 // XXX  if (0==sbutton(to, 0, sizeof(to)-1, "To: "))
1324 //              return;
1325         
1326         if (strcmp(to, from)==0)
1327                 return;
1328         
1329         SEQP_BEGIN(ed, seq) {
1330                 if(seq->flag & SELECT) {
1331                         if(strncmp(seq->strip->dir, from, strlen(from))==0) {
1332                                 printf("found %s\n", seq->strip->dir);
1333                                 
1334                                 /* strip off the beginning */
1335                                 stripped[0]= 0;
1336                                 BLI_strncpy(stripped, seq->strip->dir + strlen(from), FILE_MAX);
1337                                 
1338                                 /* new path */
1339                                 BLI_strncpy(seq->strip->dir, to, FILE_MAX);
1340                                 strcat(seq->strip->dir, stripped);
1341                                 printf("new %s\n", seq->strip->dir);
1342                         }
1343                 }
1344         }
1345         SEQ_END
1346                 
1347 }
1348
1349
1350 void no_gaps(Scene *scene)
1351 {
1352         Editing *ed= seq_give_editing(scene, FALSE);
1353         int cfra, first= 0, done;
1354
1355         
1356         if(ed==NULL) return;
1357
1358         for(cfra= CFRA; cfra<=EFRA; cfra++) {
1359                 if(first==0) {
1360                         if( evaluate_seq_frame(scene, cfra) ) first= 1;
1361                 }
1362                 else {
1363                         done= 1;
1364                         while( evaluate_seq_frame(scene, cfra) == 0) {
1365                                 done= insert_gap(scene, -1, cfra);
1366                                 if(done==0) break;
1367                         }
1368                         if(done==0) break;
1369                 }
1370         }
1371
1372 }
1373
1374 #if 0
1375 static int seq_get_snaplimit(View2D *v2d)
1376 {
1377         /* fake mouse coords to get the snap value
1378         a bit lazy but its only done once pre transform */
1379         float xmouse, ymouse, x;
1380         short mval[2] = {24, 0}; /* 24 screen px snap */
1381         
1382         UI_view2d_region_to_view(v2d, mval[0], mval[1], &xmouse, &ymouse);
1383         x = xmouse;
1384         mval[0] = 0;
1385         UI_view2d_region_to_view(v2d, mval[0], mval[1], &xmouse, &ymouse);
1386         return (int)(x - xmouse);
1387 }
1388 #endif
1389
1390 /* Operator functions */
1391
1392 /* snap operator*/
1393 static int sequencer_snap_exec(bContext *C, wmOperator *op)
1394 {
1395         Scene *scene= CTX_data_scene(C);
1396         
1397         Editing *ed= seq_give_editing(scene, FALSE);
1398         Sequence *seq;
1399         int snap_frame;
1400         
1401         if(ed==NULL) return OPERATOR_CANCELLED;
1402
1403         snap_frame= RNA_int_get(op->ptr, "frame");
1404
1405         /* problem: contents of meta's are all shifted to the same position... */
1406
1407         /* also check metas */
1408         SEQP_BEGIN(ed, seq) {
1409                 if (seq->flag & SELECT && !(seq->depth==0 && seq->flag & SEQ_LOCK) &&
1410                     seq_tx_test(seq)) {
1411                         if((seq->flag & (SEQ_LEFTSEL+SEQ_RIGHTSEL))==0) {
1412                                 seq->start= snap_frame-seq->startofs+seq->startstill;
1413                         } else { 
1414                                 if(seq->flag & SEQ_LEFTSEL) {
1415                                         seq_tx_set_final_left(seq, snap_frame);
1416                                 } else { /* SEQ_RIGHTSEL */
1417                                         seq_tx_set_final_right(seq, snap_frame);
1418                                 }
1419                                 seq_tx_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL);
1420                         }
1421                         calc_sequence(seq);
1422                 }
1423         }
1424         SEQ_END
1425
1426         /* test for effects and overlap */
1427         SEQP_BEGIN(ed, seq) {
1428                 if(seq->flag & SELECT && !(seq->depth==0 && seq->flag & SEQ_LOCK)) {
1429                         seq->flag &= ~SEQ_OVERLAP;
1430                         if( seq_test_overlap(ed->seqbasep, seq) ) {
1431                                 shuffle_seq(ed->seqbasep, seq);
1432                         }
1433                 }
1434                 else if(seq->type & SEQ_EFFECT) {
1435                         if(seq->seq1 && (seq->seq1->flag & SELECT)) 
1436                                 calc_sequence(seq);
1437                         else if(seq->seq2 && (seq->seq2->flag & SELECT)) 
1438                                 calc_sequence(seq);
1439                         else if(seq->seq3 && (seq->seq3->flag & SELECT)) 
1440                                 calc_sequence(seq);
1441                 }
1442         }
1443         SEQ_END;
1444
1445         /* as last: */
1446         sort_seq(scene);
1447         
1448         ED_area_tag_redraw(CTX_wm_area(C));
1449         
1450         return OPERATOR_FINISHED;
1451 }
1452
1453 static int sequencer_snap_invoke(bContext *C, wmOperator *op, wmEvent *event)
1454 {
1455         Scene *scene = CTX_data_scene(C);
1456         
1457         int snap_frame;
1458         
1459         snap_frame= CFRA;
1460         
1461         RNA_int_set(op->ptr, "frame", snap_frame);
1462         return sequencer_snap_exec(C, op);
1463 }
1464
1465 void SEQUENCER_OT_snap(struct wmOperatorType *ot)
1466 {
1467         /* identifiers */
1468         ot->name= "Snap strips";
1469         ot->idname= "SEQUENCER_OT_snap";
1470
1471         /* api callbacks */
1472         ot->invoke= sequencer_snap_invoke;
1473         ot->exec= sequencer_snap_exec;
1474
1475         ot->poll= ED_operator_sequencer_active;
1476         
1477         /* flags */
1478         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1479         
1480         RNA_def_int(ot->srna, "frame", 0, INT_MIN, INT_MAX, "Frame", "Frame where selected strips will snaped", INT_MIN, INT_MAX);
1481 }
1482
1483 /* mute operator */
1484 static int sequencer_mute_exec(bContext *C, wmOperator *op)
1485 {
1486         Scene *scene= CTX_data_scene(C);
1487         Editing *ed= seq_give_editing(scene, FALSE);
1488         Sequence *seq;
1489         int selected;
1490
1491         if(ed==NULL)
1492                 return OPERATOR_CANCELLED;
1493
1494         selected=  RNA_enum_is_equal(op->ptr, "type", "SELECTED");
1495         
1496         
1497         for(seq= ed->seqbasep->first; seq; seq= seq->next) {
1498                 if ((seq->flag & SEQ_LOCK)==0) {
1499                         if(selected){ /* mute unselected */
1500                                 if (seq->flag & SELECT) {
1501                                         seq->flag |= SEQ_MUTE;
1502                                 }
1503                         }
1504                         else {
1505                                 if ((seq->flag & SELECT)==0) {
1506                                         seq->flag |= SEQ_MUTE;
1507                                 }
1508                         }
1509                 }
1510         }
1511         
1512         ED_area_tag_redraw(CTX_wm_area(C));
1513         
1514         return OPERATOR_FINISHED;
1515 }
1516
1517 void SEQUENCER_OT_mute(struct wmOperatorType *ot)
1518 {
1519         /* identifiers */
1520         ot->name= "Mute Strips";
1521         ot->idname= "SEQUENCER_OT_mute";
1522
1523         /* api callbacks */
1524         ot->exec= sequencer_mute_exec;
1525
1526         ot->poll= ED_operator_sequencer_active;
1527         
1528         /* flags */
1529         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1530         
1531         RNA_def_enum(ot->srna, "type", sequencer_prop_operate_types, SEQ_SELECTED, "Type", "");
1532 }
1533
1534
1535 /* unmute operator */
1536 static int sequencer_unmute_exec(bContext *C, wmOperator *op)
1537 {
1538         Scene *scene= CTX_data_scene(C);
1539         Editing *ed= seq_give_editing(scene, FALSE);
1540         Sequence *seq;
1541         int selected;
1542
1543         if(ed==NULL)
1544                 return OPERATOR_CANCELLED;
1545
1546         selected=  RNA_enum_is_equal(op->ptr, "type", "SELECTED");
1547         
1548         
1549         for(seq= ed->seqbasep->first; seq; seq= seq->next) {
1550                 if ((seq->flag & SEQ_LOCK)==0) {
1551                         if(selected){ /* unmute unselected */
1552                                 if (seq->flag & SELECT) {
1553                                         seq->flag &= ~SEQ_MUTE;
1554                                 }
1555                         }
1556                         else {
1557                                 if ((seq->flag & SELECT)==0) {
1558                                         seq->flag &= ~SEQ_MUTE;
1559                                 }
1560                         }
1561                 }
1562         }
1563         
1564         ED_area_tag_redraw(CTX_wm_area(C));
1565         
1566         return OPERATOR_FINISHED;
1567 }
1568
1569 void SEQUENCER_OT_unmute(struct wmOperatorType *ot)
1570 {
1571         /* identifiers */
1572         ot->name= "UnMute Strips";
1573         ot->idname= "SEQUENCER_OT_unmute";
1574
1575         /* api callbacks */
1576         ot->exec= sequencer_unmute_exec;
1577
1578         ot->poll= ED_operator_sequencer_active;
1579         
1580         /* flags */
1581         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1582         
1583         RNA_def_enum(ot->srna, "type", sequencer_prop_operate_types, SEQ_SELECTED, "Type", "");
1584 }
1585
1586
1587 /* lock operator */
1588 static int sequencer_lock_exec(bContext *C, wmOperator *op)
1589 {
1590         Scene *scene= CTX_data_scene(C);
1591         Editing *ed= seq_give_editing(scene, FALSE);
1592         Sequence *seq;
1593
1594         if(ed==NULL)
1595                 return OPERATOR_CANCELLED;
1596
1597         for(seq= ed->seqbasep->first; seq; seq= seq->next) {
1598                 if (seq->flag & SELECT) {
1599                         seq->flag |= SEQ_LOCK;
1600                 }
1601         }
1602
1603         ED_area_tag_redraw(CTX_wm_area(C));
1604
1605         return OPERATOR_FINISHED;
1606 }
1607
1608 void SEQUENCER_OT_lock(struct wmOperatorType *ot)
1609 {
1610         /* identifiers */
1611         ot->name= "Lock Strips";
1612         ot->idname= "SEQUENCER_OT_lock";
1613
1614         /* api callbacks */
1615         ot->exec= sequencer_lock_exec;
1616
1617         ot->poll= ED_operator_sequencer_active;
1618         
1619         /* flags */
1620         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1621 }
1622
1623 /* unlock operator */
1624 static int sequencer_unlock_exec(bContext *C, wmOperator *op)
1625 {
1626         Scene *scene= CTX_data_scene(C);
1627         Editing *ed= seq_give_editing(scene, FALSE);
1628         Sequence *seq;
1629
1630         if(ed==NULL)
1631                 return OPERATOR_CANCELLED;
1632
1633         for(seq= ed->seqbasep->first; seq; seq= seq->next) {
1634                 if (seq->flag & SELECT) {
1635                         seq->flag &= ~SEQ_LOCK;
1636                 }
1637         }
1638
1639         ED_area_tag_redraw(CTX_wm_area(C));
1640
1641         return OPERATOR_FINISHED;
1642 }
1643
1644 void SEQUENCER_OT_unlock(struct wmOperatorType *ot)
1645 {
1646         /* identifiers */
1647         ot->name= "UnLock Strips";
1648         ot->idname= "SEQUENCER_OT_unlock";
1649
1650         /* api callbacks */
1651         ot->exec= sequencer_unlock_exec;
1652
1653         ot->poll= ED_operator_sequencer_active;
1654         
1655         /* flags */
1656         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1657 }
1658
1659 /* reload operator */
1660 static int sequencer_reload_exec(bContext *C, wmOperator *op)
1661 {
1662         Scene *scene= CTX_data_scene(C);
1663         Editing *ed= seq_give_editing(scene, FALSE);
1664         Sequence *seq;
1665
1666         if(ed==NULL)
1667                 return OPERATOR_CANCELLED;
1668
1669         for(seq= ed->seqbasep->first; seq; seq= seq->next) {
1670                 if(seq->flag & SELECT) {
1671                         update_changed_seq_and_deps(scene, seq, 0, 1);
1672                 }
1673         }
1674
1675         ED_area_tag_redraw(CTX_wm_area(C));
1676
1677         return OPERATOR_FINISHED;
1678 }
1679
1680 void SEQUENCER_OT_reload(struct wmOperatorType *ot)
1681 {
1682         /* identifiers */
1683         ot->name= "Reload Strips";
1684         ot->idname= "SEQUENCER_OT_reload";
1685
1686         /* api callbacks */
1687         ot->exec= sequencer_reload_exec;
1688
1689         ot->poll= ED_operator_sequencer_active;
1690         
1691         /* flags */
1692         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1693 }
1694
1695 /* reload operator */
1696 static int sequencer_refresh_all_exec(bContext *C, wmOperator *op)
1697 {
1698         Scene *scene= CTX_data_scene(C);
1699         Editing *ed= seq_give_editing(scene, FALSE);
1700         
1701         if(ed==NULL)
1702                 return OPERATOR_CANCELLED;
1703
1704         free_imbuf_seq(&ed->seqbase);
1705
1706         ED_area_tag_redraw(CTX_wm_area(C));
1707
1708         return OPERATOR_FINISHED;
1709 }
1710
1711 void SEQUENCER_OT_refresh_all(struct wmOperatorType *ot)
1712 {
1713         /* identifiers */
1714         ot->name= "Refresh Sequencer";
1715         ot->idname= "SEQUENCER_OT_refresh_all";
1716
1717         /* api callbacks */
1718         ot->exec= sequencer_refresh_all_exec;
1719
1720         ot->poll= ED_operator_sequencer_active;
1721         
1722         /* flags */
1723         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1724 }
1725
1726 /* cut operator */
1727 static EnumPropertyItem prop_cut_types[] = {
1728         {SEQ_CUT_SOFT, "SOFT", 0, "Soft", ""},
1729         {SEQ_CUT_HARD, "HARD", 0, "Hard", ""},
1730         {0, NULL, 0, NULL, NULL}
1731 };
1732
1733 static int sequencer_cut_exec(bContext *C, wmOperator *op)
1734 {
1735         Scene *scene= CTX_data_scene(C);
1736         Editing *ed= seq_give_editing(scene, FALSE);
1737         int cut_side, cut_hard, cut_frame;
1738
1739         ListBase newlist;
1740         int changed;
1741         
1742         if(ed==NULL)
1743                 return OPERATOR_CANCELLED;
1744
1745         cut_frame= RNA_int_get(op->ptr, "frame");
1746         cut_hard= RNA_enum_get(op->ptr, "type");
1747         cut_side= RNA_enum_get(op->ptr, "side");
1748         
1749         newlist.first= newlist.last= NULL;
1750
1751         if (cut_hard==SEQ_CUT_HARD) {
1752                 changed = cut_seq_list(scene,
1753                         ed->seqbasep, &newlist, cut_frame, cut_seq_hard);
1754         } else {
1755                 changed = cut_seq_list(scene,
1756                         ed->seqbasep, &newlist, cut_frame, cut_seq_soft);
1757         }
1758         
1759         if (newlist.first) { /* got new strips ? */
1760                 Sequence *seq;
1761                 addlisttolist(ed->seqbasep, &newlist);
1762
1763                 if (cut_side != SEQ_SIDE_BOTH) {
1764                         SEQP_BEGIN(ed, seq) {
1765                                 if (cut_side==SEQ_SIDE_LEFT) {
1766                                         if ( seq->startdisp >= cut_frame ) {
1767                                                 seq->flag &= SEQ_DESEL;
1768                                         }
1769                                 } else {
1770                                         if ( seq->enddisp <= cut_frame ) {
1771                                                 seq->flag &= SEQ_DESEL;
1772                                         }
1773                                 }
1774                         }
1775                         SEQ_END;
1776                 }
1777                 /* as last: */
1778                 sort_seq(scene);
1779         }
1780
1781         if (changed) {
1782                 ED_area_tag_redraw(CTX_wm_area(C));
1783         }
1784         
1785         return OPERATOR_FINISHED;
1786 }
1787
1788
1789 static int sequencer_cut_invoke(bContext *C, wmOperator *op, wmEvent *event)
1790 {
1791         Scene *scene = CTX_data_scene(C);
1792         ARegion *ar= CTX_wm_region(C);
1793         View2D *v2d= UI_view2d_fromcontext(C);
1794         
1795         int cut_side, cut_frame;
1796         
1797         cut_frame= CFRA;
1798         cut_side= mouse_frame_side(v2d, event->x - ar->winrct.xmin, cut_frame);
1799         
1800         RNA_int_set(op->ptr, "frame", cut_frame);
1801         RNA_enum_set(op->ptr, "side", cut_side);
1802         /*RNA_enum_set(op->ptr, "type", cut_hard); */ /*This type is set from the key shortcut */
1803
1804         return sequencer_cut_exec(C, op);
1805 }
1806
1807
1808 void SEQUENCER_OT_cut(struct wmOperatorType *ot)
1809 {
1810         /* identifiers */
1811         ot->name= "Cut Strips";
1812         ot->idname= "SEQUENCER_OT_cut";
1813
1814         /* api callbacks */
1815         ot->invoke= sequencer_cut_invoke;
1816         ot->exec= sequencer_cut_exec;
1817
1818         ot->poll= ED_operator_sequencer_active;
1819         
1820         /* flags */
1821         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1822         
1823         RNA_def_int(ot->srna, "frame", 0, INT_MIN, INT_MAX, "Frame", "Frame where selected strips will be cut", INT_MIN, INT_MAX);
1824         RNA_def_enum(ot->srna, "type", prop_cut_types, SEQ_CUT_SOFT, "Type", "the type of cut operation to perform on strips");
1825         RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side that remains selected after cutting");
1826 }
1827
1828 /* duplicate operator */
1829 static int sequencer_add_duplicate_exec(bContext *C, wmOperator *op)
1830 {
1831         Scene *scene= CTX_data_scene(C);
1832         Editing *ed= seq_give_editing(scene, FALSE);
1833
1834         ListBase new= {NULL, NULL};
1835
1836         if(ed==NULL)
1837                 return OPERATOR_CANCELLED;
1838
1839         recurs_dupli_seq(scene, ed->seqbasep, &new);
1840         addlisttolist(ed->seqbasep, &new);
1841
1842         ED_area_tag_redraw(CTX_wm_area(C));
1843
1844         return OPERATOR_FINISHED;
1845 }
1846
1847 static int sequencer_add_duplicate_invoke(bContext *C, wmOperator *op, wmEvent *event)
1848 {
1849         sequencer_add_duplicate_exec(C, op);
1850
1851         RNA_int_set(op->ptr, "mode", TFM_TRANSLATION);
1852         WM_operator_name_call(C, "TFM_OT_transform", WM_OP_INVOKE_REGION_WIN, op->ptr);
1853
1854         return OPERATOR_FINISHED;
1855 }
1856
1857 void SEQUENCER_OT_duplicate_add(wmOperatorType *ot)
1858 {
1859
1860         /* identifiers */
1861         ot->name= "Add Duplicate";
1862         ot->idname= "SEQUENCER_OT_duplicate_add";
1863
1864         /* api callbacks */
1865         ot->invoke= sequencer_add_duplicate_invoke;
1866         ot->exec= sequencer_add_duplicate_exec;
1867
1868         ot->poll= ED_operator_sequencer_active;
1869         
1870         /* flags */
1871         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1872         
1873         /* to give to transform */
1874         RNA_def_int(ot->srna, "mode", TFM_TRANSLATION, 0, INT_MAX, "Mode", "", 0, INT_MAX);
1875 }
1876
1877 /* delete operator */
1878 static int sequencer_delete_exec(bContext *C, wmOperator *op)
1879 {
1880         Scene *scene= CTX_data_scene(C);
1881         Editing *ed= seq_give_editing(scene, FALSE);
1882         Sequence *seq;
1883         MetaStack *ms;
1884         int nothingSelected = TRUE;
1885
1886         if(ed==NULL)
1887                 return OPERATOR_CANCELLED;
1888
1889         seq=get_last_seq(scene);
1890         if (seq && seq->flag & SELECT) { /* avoid a loop since this is likely to be selected */
1891                 nothingSelected = FALSE;
1892         } else {
1893                 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
1894                         if (seq->flag & SELECT) {
1895                                 nothingSelected = FALSE;
1896                                 break;
1897                         }
1898                 }
1899         }
1900
1901         if (nothingSelected)
1902                 return OPERATOR_FINISHED;
1903
1904         /* free imbufs of all dependent strips */
1905         for(seq=ed->seqbasep->first; seq; seq=seq->next)
1906                 if(seq->flag & SELECT)
1907                         update_changed_seq_and_deps(scene, seq, 1, 0);
1908
1909         /* for effects, try to find a replacement input */
1910         for(seq=ed->seqbasep->first; seq; seq=seq->next)
1911                 if((seq->type & SEQ_EFFECT) && !(seq->flag & SELECT))
1912                         del_seq_find_replace_recurs(scene, seq);
1913
1914         /* delete all selected strips */
1915         recurs_del_seq_flag(scene, ed->seqbasep, SELECT, 0);
1916
1917         /* updates lengths etc */
1918         seq= ed->seqbasep->first;
1919         while(seq) {
1920                 calc_sequence(seq);
1921                 seq= seq->next;
1922         }
1923
1924         /* free parent metas */
1925         ms= ed->metastack.last;
1926         while(ms) {
1927                 ms->parseq->strip->len= 0;              /* force new alloc */
1928                 calc_sequence(ms->parseq);
1929                 ms= ms->prev;
1930         }
1931
1932         //ED_area_tag_redraw(CTX_wm_area(C));
1933         WM_event_add_notifier(C, NC_SCENE|ND_SEQUENCER, NULL); /* redraw other sequencer views */
1934         
1935         return OPERATOR_FINISHED;
1936 }
1937
1938
1939 void SEQUENCER_OT_delete(wmOperatorType *ot)
1940 {
1941
1942         /* identifiers */
1943         ot->name= "Erase Strips";
1944         ot->idname= "SEQUENCER_OT_delete";
1945
1946         /* api callbacks */
1947         ot->invoke= WM_operator_confirm;
1948         ot->exec= sequencer_delete_exec;
1949
1950         ot->poll= ED_operator_sequencer_active;
1951         
1952         /* flags */
1953         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
1954 }
1955
1956
1957 /* separate_images operator */
1958 static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
1959 {
1960         Scene *scene= CTX_data_scene(C);
1961         Editing *ed= seq_give_editing(scene, FALSE);
1962         
1963         Sequence *seq, *seq_new, *seq_next;
1964         Strip *strip_new;
1965         StripElem *se, *se_new;
1966         int start_ofs, cfra, frame_end;
1967         static int step= 1;
1968
1969 //      add_numbut(0, NUM|INT, "Image Duration:", 1, 256, &step, NULL);
1970 //      if (!do_clever_numbuts("Separate Images", 1, REDRAW))
1971 //              return;
1972
1973         if(ed==NULL)
1974                 return OPERATOR_CANCELLED;
1975
1976         seq= ed->seqbasep->first;
1977
1978         while (seq) {
1979                 if((seq->flag & SELECT) && (seq->type == SEQ_IMAGE) && (seq->len > 1)) {
1980                         /* remove seq so overlap tests dont conflict,
1981                         see seq_free_sequence below for the real free'ing */
1982                         seq_next = seq->next;
1983                         BLI_remlink(ed->seqbasep, seq);
1984                         if(seq->ipo) seq->ipo->id.us--;
1985
1986                         start_ofs = cfra = seq_tx_get_final_left(seq, 0);
1987                         frame_end = seq_tx_get_final_right(seq, 0);
1988
1989                         while (cfra < frame_end) {
1990                                 /* new seq */
1991                                 se = give_stripelem(seq, cfra);
1992
1993                                 seq_new= alloc_sequence(ed->seqbasep, start_ofs, seq->machine);
1994                                 seq_new->type= SEQ_IMAGE;
1995                                 seq_new->len = 1;
1996                                 seq_new->endstill = step-1;
1997
1998                                 /* new strip */
1999                                 seq_new->strip= strip_new= MEM_callocN(sizeof(Strip)*1, "strip");
2000                                 strip_new->len= 1;
2001                                 strip_new->us= 1;
2002                                 strncpy(strip_new->dir, seq->strip->dir, FILE_MAXDIR-1);
2003
2004                                 /* new stripdata */
2005                                 strip_new->stripdata= se_new= MEM_callocN(sizeof(StripElem)*1, "stripelem");
2006                                 strncpy(se_new->name, se->name, FILE_MAXFILE-1);
2007                                 calc_sequence(seq_new);
2008                                 seq_new->flag &= ~SEQ_OVERLAP;
2009                                 if (seq_test_overlap(ed->seqbasep, seq_new)) {
2010                                         shuffle_seq(ed->seqbasep, seq_new);
2011                                 }
2012
2013                                 cfra++;
2014                                 start_ofs += step;
2015                         }
2016
2017                         seq_free_sequence(ed, seq);
2018                         seq = seq->next;
2019                 } else {
2020                         seq = seq->next;
2021                 }
2022         }
2023
2024         /* as last: */
2025         sort_seq(scene);
2026         
2027         ED_area_tag_redraw(CTX_wm_area(C));
2028
2029         return OPERATOR_FINISHED;
2030 }
2031
2032
2033 void SEQUENCER_OT_images_separate(wmOperatorType *ot)
2034 {
2035         /* identifiers */
2036         ot->name= "Separate Images";
2037         ot->idname= "SEQUENCER_OT_images_separate";
2038
2039         /* api callbacks */
2040         ot->invoke= WM_operator_confirm;
2041         ot->exec= sequencer_separate_images_exec;
2042
2043         ot->poll= ED_operator_sequencer_active;
2044         
2045         /* flags */
2046         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2047 }
2048
2049
2050 /* META Operators */
2051
2052 /* separate_meta_toggle operator */
2053 static int sequencer_meta_toggle_exec(bContext *C, wmOperator *op)
2054 {
2055         Scene *scene= CTX_data_scene(C);
2056         Editing *ed= seq_give_editing(scene, FALSE);
2057         Sequence *last_seq= get_last_seq(scene);
2058         MetaStack *ms;
2059
2060         if(ed==NULL)
2061                 return OPERATOR_CANCELLED;
2062
2063         if(last_seq && last_seq->type==SEQ_META && last_seq->flag & SELECT) {
2064                 /* Enter Metastrip */
2065                 ms= MEM_mallocN(sizeof(MetaStack), "metastack");
2066                 BLI_addtail(&ed->metastack, ms);
2067                 ms->parseq= last_seq;
2068                 ms->oldbasep= ed->seqbasep;
2069
2070                 ed->seqbasep= &last_seq->seqbase;
2071
2072                 set_last_seq(scene, NULL);
2073
2074         }
2075         else {
2076                 /* Exit Metastrip (if possible) */
2077
2078                 Sequence *seq;
2079
2080                 if(ed->metastack.first==NULL)
2081                         return OPERATOR_CANCELLED;
2082
2083                 ms= ed->metastack.last;
2084                 BLI_remlink(&ed->metastack, ms);
2085
2086                 ed->seqbasep= ms->oldbasep;
2087
2088                 /* recalc all: the meta can have effects connected to it */
2089                 for(seq= ed->seqbasep->first; seq; seq= seq->next)
2090                         calc_sequence(seq);
2091
2092                 set_last_seq(scene, ms->parseq);
2093
2094                 ms->parseq->flag |= SELECT;
2095                 recurs_sel_seq(ms->parseq);
2096
2097                 MEM_freeN(ms);
2098
2099         }
2100
2101         ED_area_tag_redraw(CTX_wm_area(C));
2102         return OPERATOR_FINISHED;
2103 }
2104
2105 void SEQUENCER_OT_meta_toggle(wmOperatorType *ot)
2106 {
2107         /* identifiers */
2108         ot->name= "Toggle Meta Strip";
2109         ot->idname= "SEQUENCER_OT_meta_toggle";
2110
2111         /* api callbacks */
2112         ot->exec= sequencer_meta_toggle_exec;
2113
2114         ot->poll= ED_operator_sequencer_active;
2115         
2116         /* flags */
2117         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2118 }
2119
2120
2121 /* separate_meta_make operator */
2122 static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
2123 {
2124         Scene *scene= CTX_data_scene(C);
2125         Editing *ed= seq_give_editing(scene, FALSE);
2126         
2127         Sequence *seq, *seqm, *next;
2128         
2129         int tot;
2130
2131         if(ed==NULL)
2132                 return OPERATOR_CANCELLED;
2133
2134         /* is there more than 1 select */
2135         tot= 0;
2136         seq= ed->seqbasep->first;
2137         while(seq) {
2138                 if(seq->flag & SELECT) {
2139                         tot++;
2140                         if (seq->type == SEQ_RAM_SOUND) {
2141                                 BKE_report(op->reports, RPT_ERROR, "Can't make Meta Strip from audio");
2142                                 return OPERATOR_CANCELLED;;
2143                         }
2144                 }
2145                 seq= seq->next;
2146         }
2147         if(tot < 1) return OPERATOR_CANCELLED;;
2148
2149
2150         /* test relationships */
2151         seq= ed->seqbasep->first;
2152         while(seq) {
2153                 if(seq->flag & SELECT) {
2154                         if(seq->type & SEQ_EFFECT) {
2155                                 if(seq->seq1 &&
2156                                    (seq->seq1->flag & SELECT)==0) tot= 0;
2157                                 if(seq->seq2 &&
2158                                    (seq->seq2->flag & SELECT)==0) tot= 0;
2159                                 if(seq->seq3 &&
2160                                    (seq->seq3->flag & SELECT)==0) tot= 0;
2161                         }
2162                 }
2163                 else if(seq->type & SEQ_EFFECT) {
2164                         if(seq->seq1 &&
2165                            (seq->seq1->flag & SELECT)) tot= 0;
2166                         if(seq->seq2 &&
2167                            (seq->seq2->flag & SELECT)) tot= 0;
2168                         if(seq->seq3 &&
2169                            (seq->seq3->flag & SELECT)) tot= 0;
2170                 }
2171                 if(tot==0) break;
2172                 seq= seq->next;
2173         }
2174
2175         if(tot==0) {
2176                 BKE_report(op->reports, RPT_ERROR, "Please select all related strips");
2177                 return OPERATOR_CANCELLED;
2178         }
2179
2180         /* remove all selected from main list, and put in meta */
2181
2182         seqm= alloc_sequence(ed->seqbasep, 1, 1);
2183         seqm->type= SEQ_META;
2184         seqm->flag= SELECT;
2185
2186         seq= ed->seqbasep->first;
2187         while(seq) {
2188                 next= seq->next;
2189                 if(seq!=seqm && (seq->flag & SELECT)) {
2190                         BLI_remlink(ed->seqbasep, seq);
2191                         BLI_addtail(&seqm->seqbase, seq);
2192                 }
2193                 seq= next;
2194         }
2195         calc_sequence(seqm);
2196
2197         seqm->strip= MEM_callocN(sizeof(Strip), "metastrip");
2198         seqm->strip->len= seqm->len;
2199         seqm->strip->us= 1;
2200         
2201         set_last_seq(scene, seqm);
2202
2203         if( seq_test_overlap(ed->seqbasep, seqm) ) shuffle_seq(ed->seqbasep, seqm);
2204
2205         ED_area_tag_redraw(CTX_wm_area(C));
2206         return OPERATOR_FINISHED;
2207 }
2208
2209 void SEQUENCER_OT_meta_make(wmOperatorType *ot)
2210 {
2211         /* identifiers */
2212         ot->name= "Make Meta Strip";
2213         ot->idname= "SEQUENCER_OT_meta_make";
2214
2215         /* api callbacks */
2216         ot->invoke= WM_operator_confirm;
2217         ot->exec= sequencer_meta_make_exec;
2218
2219         ot->poll= ED_operator_sequencer_active;
2220         
2221         /* flags */
2222         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2223 }
2224
2225
2226 static int seq_depends_on_meta(Sequence *seq, Sequence *seqm)
2227 {
2228         if (seq == seqm) return 1;
2229         else if (seq->seq1 && seq_depends_on_meta(seq->seq1, seqm)) return 1;
2230         else if (seq->seq2 && seq_depends_on_meta(seq->seq2, seqm)) return 1;
2231         else if (seq->seq3 && seq_depends_on_meta(seq->seq3, seqm)) return 1;
2232         else return 0;
2233 }
2234
2235 /* separate_meta_make operator */
2236 static int sequencer_meta_separate_exec(bContext *C, wmOperator *op)
2237 {
2238         Scene *scene= CTX_data_scene(C);
2239         Editing *ed= seq_give_editing(scene, FALSE);
2240
2241         Sequence *seq, *last_seq = get_last_seq(scene); /* last_seq checks ed==NULL */
2242
2243         if(last_seq==NULL || last_seq->type!=SEQ_META)
2244                 return OPERATOR_CANCELLED;
2245
2246         addlisttolist(ed->seqbasep, &last_seq->seqbase);
2247
2248         last_seq->seqbase.first= 0;
2249         last_seq->seqbase.last= 0;
2250
2251         BLI_remlink(ed->seqbasep, last_seq);
2252         seq_free_sequence(ed, last_seq);
2253
2254         /* emtpy meta strip, delete all effects depending on it */
2255         for(seq=ed->seqbasep->first; seq; seq=seq->next)
2256                 if((seq->type & SEQ_EFFECT) && seq_depends_on_meta(seq, last_seq))
2257                         seq->flag |= SEQ_FLAG_DELETE;
2258
2259         recurs_del_seq_flag(scene, ed->seqbasep, SEQ_FLAG_DELETE, 0);
2260
2261         /* test for effects and overlap */
2262         SEQP_BEGIN(ed, seq) {
2263                 if(seq->flag & SELECT) {
2264                         seq->flag &= ~SEQ_OVERLAP;
2265                         if( seq_test_overlap(ed->seqbasep, seq) ) {
2266                                 shuffle_seq(ed->seqbasep, seq);
2267                         }
2268                 }
2269         }
2270         SEQ_END;
2271
2272         sort_seq(scene);
2273
2274         ED_area_tag_redraw(CTX_wm_area(C));
2275         return OPERATOR_FINISHED;
2276 }
2277
2278 void SEQUENCER_OT_meta_separate(wmOperatorType *ot)
2279 {
2280         /* identifiers */
2281         ot->name= "UnMeta Strip";
2282         ot->idname= "SEQUENCER_OT_meta_separate";
2283
2284         /* api callbacks */
2285         ot->invoke= WM_operator_confirm;
2286         ot->exec= sequencer_meta_separate_exec;
2287
2288         ot->poll= ED_operator_sequencer_active;
2289         
2290         /* flags */
2291         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
2292 }
2293
2294 /* view_all operator */
2295 static int sequencer_view_all_exec(bContext *C, wmOperator *op)
2296 {
2297         Scene *scene= CTX_data_scene(C);
2298         bScreen *sc= CTX_wm_screen(C);
2299         ScrArea *area= CTX_wm_area(C);
2300         ARegion *ar= CTX_wm_region(C);
2301         SpaceSeq *sseq= area->spacedata.first;
2302         View2D *v2d= UI_view2d_fromcontext(C);
2303
2304         if (sseq->mainb==SEQ_DRAW_SEQUENCE) {
2305                 v2d->cur= v2d->tot;
2306                 UI_view2d_curRect_validate(v2d);
2307                 UI_view2d_sync(sc, area, v2d, V2D_LOCK_COPY);
2308         } else {
2309                 /* Like zooming on an image view */
2310                 float zoomX, zoomY;
2311                 int width, height, imgwidth, imgheight;
2312
2313                 width = ar->winx;
2314                 height = ar->winy;
2315
2316                 seq_reset_imageofs(sseq);
2317
2318                 imgwidth= (scene->r.size*scene->r.xsch)/100;
2319                 imgheight= (scene->r.size*scene->r.ysch)/100;
2320
2321                 /* Apply aspect, dosnt need to be that accurate */
2322                 imgwidth= (int)(imgwidth * ((float)scene->r.xasp / (float)scene->r.yasp));
2323
2324                 if (((imgwidth >= width) || (imgheight >= height)) &&
2325                         ((width > 0) && (height > 0))) {
2326
2327                         /* Find the zoom value that will fit the image in the image space */
2328                         zoomX = ((float)width) / ((float)imgwidth);
2329                         zoomY = ((float)height) / ((float)imgheight);
2330                         sseq->zoom= (zoomX < zoomY) ? zoomX : zoomY;
2331
2332                         sseq->zoom = 1.0f / power_of_2(1/ MIN2(zoomX, zoomY) );
2333                 }
2334                 else {
2335                         sseq->zoom= 1.0f;
2336                 }
2337         }
2338
2339
2340         ED_area_tag_redraw(CTX_wm_area(C));
2341         return OPERATOR_FINISHED;
2342 }
2343
2344 void SEQUENCER_OT_view_all(wmOperatorType *ot)
2345 {
2346         /* identifiers */
2347         ot->name= "View All";
2348         ot->idname= "SEQUENCER_OT_view_all";
2349
2350         /* api callbacks */
2351         ot->exec= sequencer_view_all_exec;
2352
2353         ot->poll= ED_operator_sequencer_active;
2354         
2355         /* flags */
2356         ot->flag= OPTYPE_REGISTER;
2357 }
2358
2359
2360 /* view_all operator */
2361 static int sequencer_view_selected_exec(bContext *C, wmOperator *op)
2362 {
2363         Scene *scene= CTX_data_scene(C);
2364         View2D *v2d= UI_view2d_fromcontext(C);
2365         ScrArea *area= CTX_wm_area(C);
2366         bScreen *sc= CTX_wm_screen(C);
2367         Editing *ed= seq_give_editing(scene, FALSE);
2368         Sequence *seq;
2369
2370         int xmin=  MAXFRAME*2;
2371         int xmax= -MAXFRAME*2;
2372         int ymin=  MAXSEQ+1;
2373         int ymax= 0;
2374         int orig_height;
2375         int ymid;
2376         int ymargin= 1;
2377         int xmargin= FPS;
2378
2379         if(ed==NULL)
2380                 return OPERATOR_CANCELLED;
2381
2382         for(seq=ed->seqbasep->first; seq; seq=seq->next) {
2383                 if(seq->flag & SELECT) {
2384                         xmin= MIN2(xmin, seq->startdisp);
2385                         xmax= MAX2(xmax, seq->enddisp);
2386
2387                         ymin= MIN2(ymin, seq->machine);
2388                         ymax= MAX2(ymax, seq->machine);
2389                 }
2390         }
2391
2392         if (ymax != 0) {
2393                 
2394                 xmax += xmargin;
2395                 xmin -= xmargin;
2396                 ymax += ymargin;
2397                 ymin -= ymargin;
2398
2399                 orig_height= v2d->cur.ymax - v2d->cur.ymin;
2400
2401                 v2d->cur.xmin= xmin;
2402                 v2d->cur.xmax= xmax;
2403
2404                 v2d->cur.ymin= ymin;
2405                 v2d->cur.ymax= ymax;
2406
2407                 /* only zoom out vertically */
2408                 if (orig_height > v2d->cur.ymax - v2d->cur.ymin) {
2409                         ymid= (v2d->cur.ymax + v2d->cur.ymin) / 2;
2410
2411                         v2d->cur.ymin= ymid - (orig_height/2);
2412                         v2d->cur.ymax= ymid + (orig_height/2);
2413                 }
2414
2415                 UI_view2d_curRect_validate(v2d);
2416                 UI_view2d_sync(sc, area, v2d, V2D_LOCK_COPY);
2417
2418                 ED_area_tag_redraw(CTX_wm_area(C));
2419         }
2420         
2421         return OPERATOR_FINISHED;
2422 }
2423
2424 void SEQUENCER_OT_view_selected(wmOperatorType *ot)
2425 {
2426         /* identifiers */
2427         ot->name= "View Selected";
2428         ot->idname= "SEQUENCER_OT_view_selected";
2429
2430         /* api callbacks */
2431         ot->exec= sequencer_view_selected_exec;
2432
2433         ot->poll= ED_operator_sequencer_active;
2434         
2435         /* flags */
2436         ot->flag= OPTYPE_REGISTER;
2437 }