2 * ***** begin GPL LICENSE BLOCK *****
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software Foundation,
16 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
19 * All rights reserved.
21 * Contributor(s): Blender Foundation, 2003-2009
23 * ***** END GPL LICENSE BLOCK *****
26 /** \file blender/editors/space_sequencer/sequencer_edit.c
40 #include <sys/types.h>
42 #include "MEM_guardedalloc.h"
44 #include "BLI_blenlib.h"
46 #include "BLI_utildefines.h"
47 #include "BLI_threads.h"
49 #include "BLF_translation.h"
51 #include "DNA_scene_types.h"
52 #include "DNA_userdef_types.h"
54 #include "BKE_context.h"
55 #include "BKE_global.h"
57 #include "BKE_sequencer.h"
58 #include "BKE_report.h"
59 #include "BKE_sound.h"
60 #include "BKE_movieclip.h"
62 #include "IMB_imbuf.h"
67 #include "RNA_define.h"
68 #include "RNA_enum_types.h"
70 /* for menu/popup icons etc etc*/
72 #include "ED_screen.h"
73 #include "ED_transform.h"
74 #include "ED_sequencer.h"
76 #include "UI_view2d.h"
79 #include "sequencer_intern.h"
82 /* RNA Enums, used in multiple files */
83 EnumPropertyItem sequencer_prop_effect_types[] = {
84 {SEQ_TYPE_CROSS, "CROSS", 0, "Crossfade", "Crossfade effect strip type"},
85 {SEQ_TYPE_ADD, "ADD", 0, "Add", "Add effect strip type"},
86 {SEQ_TYPE_SUB, "SUBTRACT", 0, "Subtract", "Subtract effect strip type"},
87 {SEQ_TYPE_ALPHAOVER, "ALPHA_OVER", 0, "Alpha Over", "Alpha Over effect strip type"},
88 {SEQ_TYPE_ALPHAUNDER, "ALPHA_UNDER", 0, "Alpha Under", "Alpha Under effect strip type"},
89 {SEQ_TYPE_GAMCROSS, "GAMMA_CROSS", 0, "Gamma Cross", "Gamma Cross effect strip type"},
90 {SEQ_TYPE_MUL, "MULTIPLY", 0, "Multiply", "Multiply effect strip type"},
91 {SEQ_TYPE_OVERDROP, "OVER_DROP", 0, "Alpha Over Drop", "Alpha Over Drop effect strip type"},
92 {SEQ_TYPE_WIPE, "WIPE", 0, "Wipe", "Wipe effect strip type"},
93 {SEQ_TYPE_GLOW, "GLOW", 0, "Glow", "Glow effect strip type"},
94 {SEQ_TYPE_TRANSFORM, "TRANSFORM", 0, "Transform", "Transform effect strip type"},
95 {SEQ_TYPE_COLOR, "COLOR", 0, "Color", "Color effect strip type"},
96 {SEQ_TYPE_SPEED, "SPEED", 0, "Speed", "Color effect strip type"},
97 {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
98 {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
99 {0, NULL, 0, NULL, NULL}
104 EnumPropertyItem prop_side_types[] = {
105 {SEQ_SIDE_LEFT, "LEFT", 0, "Left", ""},
106 {SEQ_SIDE_RIGHT, "RIGHT", 0, "Right", ""},
107 {SEQ_SIDE_BOTH, "BOTH", 0, "Both", ""},
108 {0, NULL, 0, NULL, NULL}
111 static EnumPropertyItem prop_side_lr_types[] = {
112 {SEQ_SIDE_LEFT, "LEFT", 0, "Left", ""},
113 {SEQ_SIDE_RIGHT, "RIGHT", 0, "Right", ""},
114 {0, NULL, 0, NULL, NULL}
117 typedef struct TransSeq {
119 int startstill, endstill;
120 int startdisp, enddisp;
121 int startofs, endofs;
122 int anim_startofs, anim_endofs;
123 /* int final_left, final_right; */ /* UNUSED */
127 /* ********************************************************************** */
129 /* ***************** proxy job manager ********************** */
131 typedef struct ProxyBuildJob {
138 static void proxy_freejob(void *pjv)
142 BLI_freelistN(&pj->queue);
147 /* only this runs inside thread */
148 static void proxy_startjob(void *pjv, short *stop, short *do_update, float *progress)
153 for (link = pj->queue.first; link; link = link->next) {
154 struct SeqIndexBuildContext *context = link->data;
156 BKE_sequencer_proxy_rebuild(context, stop, do_update, progress);
161 fprintf(stderr, "Canceling proxy rebuild on users request...\n");
165 static void proxy_endjob(void *pjv)
168 Editing *ed = BKE_sequencer_editing_get(pj->scene, false);
171 for (link = pj->queue.first; link; link = link->next) {
172 BKE_sequencer_proxy_rebuild_finish(link->data, pj->stop);
175 BKE_sequencer_free_imbuf(pj->scene, &ed->seqbase, false);
177 WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, pj->scene);
180 static void seq_proxy_build_job(const bContext *C)
184 Scene *scene = CTX_data_scene(C);
185 Editing *ed = BKE_sequencer_editing_get(scene, false);
186 ScrArea *sa = CTX_wm_area(C);
187 struct SeqIndexBuildContext *context;
191 wm_job = WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), sa, "Building Proxies",
192 WM_JOB_PROGRESS, WM_JOB_TYPE_SEQ_BUILD_PROXY);
194 pj = WM_jobs_customdata_get(wm_job);
197 pj = MEM_callocN(sizeof(ProxyJob), "proxy rebuild job");
200 pj->main = CTX_data_main(C);
202 WM_jobs_customdata_set(wm_job, pj, proxy_freejob);
203 WM_jobs_timer(wm_job, 0.1, NC_SCENE | ND_SEQUENCER, NC_SCENE | ND_SEQUENCER);
204 WM_jobs_callbacks(wm_job, proxy_startjob, NULL, NULL, proxy_endjob);
209 if ((seq->flag & SELECT)) {
210 context = BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq);
211 link = BLI_genericNodeN(context);
212 BLI_addtail(&pj->queue, link);
217 if (!WM_jobs_is_running(wm_job)) {
219 WM_jobs_start(CTX_wm_manager(C), wm_job);
222 ED_area_tag_redraw(CTX_wm_area(C));
225 /* ********************************************************************** */
227 void seq_rectf(Sequence *seq, rctf *rectf)
229 if (seq->startstill) rectf->xmin = seq->start;
230 else rectf->xmin = seq->startdisp;
231 rectf->ymin = seq->machine + SEQ_STRIP_OFSBOTTOM;
232 if (seq->endstill) rectf->xmax = seq->start + seq->len;
233 else rectf->xmax = seq->enddisp;
234 rectf->ymax = seq->machine + SEQ_STRIP_OFSTOP;
237 void boundbox_seq(Scene *scene, rctf *rect)
240 Editing *ed = BKE_sequencer_editing_get(scene, false);
241 float min[2], max[2];
244 if (ed == NULL) return;
251 seq = ed->seqbasep->first;
254 if (min[0] > seq->startdisp - 1) min[0] = seq->startdisp - 1;
255 if (max[0] < seq->enddisp + 1) max[0] = seq->enddisp + 1;
256 if (max[1] < seq->machine + 2) max[1] = seq->machine + 2;
268 static int mouse_frame_side(View2D *v2d, short mouse_x, int frame)
276 /* choose the side based on which side of the playhead the mouse is on */
277 UI_view2d_region_to_view(v2d, mval[0], mval[1], &mouseloc[0], &mouseloc[1]);
279 return mouseloc[0] > frame ? SEQ_SIDE_RIGHT : SEQ_SIDE_LEFT;
283 Sequence *find_neighboring_sequence(Scene *scene, Sequence *test, int lr, int sel)
285 /* sel - 0==unselected, 1==selected, -1==done care*/
287 Editing *ed = BKE_sequencer_editing_get(scene, false);
289 if (ed == NULL) return NULL;
291 if (sel > 0) sel = SELECT;
293 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
295 (test->machine == seq->machine) &&
296 ((sel == -1) || (sel && (seq->flag & SELECT)) || (sel == 0 && (seq->flag & SELECT) == 0)))
300 if (test->startdisp == (seq->enddisp)) {
305 if (test->enddisp == (seq->startdisp)) {
315 static Sequence *find_next_prev_sequence(Scene *scene, Sequence *test, int lr, int sel)
317 /* sel - 0==unselected, 1==selected, -1==done care*/
318 Sequence *seq, *best_seq = NULL;
319 Editing *ed = BKE_sequencer_editing_get(scene, false);
322 best_dist = MAXFRAME * 2;
325 if (ed == NULL) return NULL;
327 seq = ed->seqbasep->first;
330 (test->machine == seq->machine) &&
331 (test->depth == seq->depth) &&
332 ((sel == -1) || (sel == (seq->flag & SELECT))))
338 if (seq->enddisp <= test->startdisp) {
339 dist = test->enddisp - seq->startdisp;
343 if (seq->startdisp >= test->enddisp) {
344 dist = seq->startdisp - test->enddisp;
353 else if (dist < best_dist) {
360 return best_seq; /* can be null */
364 Sequence *find_nearest_seq(Scene *scene, View2D *v2d, int *hand, const int mval[2])
367 Editing *ed = BKE_sequencer_editing_get(scene, false);
372 *hand = SEQ_SIDE_NONE;
375 if (ed == NULL) return NULL;
377 pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
379 UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
381 seq = ed->seqbasep->first;
384 if (seq->machine == (int)y) {
385 /* check for both normal strips, and strips that have been flipped horizontally */
386 if (((seq->startdisp < seq->enddisp) && (seq->startdisp <= x && seq->enddisp >= x)) ||
387 ((seq->startdisp > seq->enddisp) && (seq->startdisp >= x && seq->enddisp <= x)) )
389 if (BKE_sequence_tx_test(seq)) {
391 /* clamp handles to defined size in pixel space */
393 handsize = seq->handsize;
394 displen = (float)abs(seq->startdisp - seq->enddisp);
396 if (displen / pixelx > 16) { /* don't even try to grab the handles of small strips */
397 /* Set the max value to handle to 1/3 of the total len when its less then 28.
398 * This is important because otherwise selecting handles happens even when you click in the middle */
400 if ((displen / 3) < 30 * pixelx) {
401 handsize = displen / 3;
404 CLAMP(handsize, 7 * pixelx, 30 * pixelx);
407 if (handsize + seq->startdisp >= x)
408 *hand = SEQ_SIDE_LEFT;
409 else if (-handsize + seq->enddisp <= x)
410 *hand = SEQ_SIDE_RIGHT;
422 static bool seq_is_parent(Sequence *par, Sequence *seq)
424 return ((par->seq1 == seq) || (par->seq2 == seq) || (par->seq3 == seq));
427 static bool seq_is_predecessor(Sequence *pred, Sequence *seq)
430 if (pred == seq) return 0;
431 else if (seq_is_parent(pred, seq)) return 1;
432 else if (pred->seq1 && seq_is_predecessor(pred->seq1, seq)) return 1;
433 else if (pred->seq2 && seq_is_predecessor(pred->seq2, seq)) return 1;
434 else if (pred->seq3 && seq_is_predecessor(pred->seq3, seq)) return 1;
439 void ED_sequencer_deselect_all(Scene *scene)
442 Editing *ed = BKE_sequencer_editing_get(scene, false);
445 if (ed == NULL) return;
449 seq->flag &= ~SEQ_ALLSEL;
455 void recurs_sel_seq(Sequence *seqm)
459 seq = seqm->seqbase.first;
462 if (seqm->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) seq->flag &= ~SEQ_ALLSEL;
463 else if (seqm->flag & SELECT) seq->flag |= SELECT;
464 else seq->flag &= ~SEQ_ALLSEL;
466 if (seq->seqbase.first) recurs_sel_seq(seq);
472 int ED_space_sequencer_maskedit_mask_poll(bContext *C)
474 /* in this case both funcs are the same, for clip editor not */
475 return ED_space_sequencer_maskedit_poll(C);
478 bool ED_space_sequencer_check_show_maskedit(SpaceSeq *sseq, Scene *scene)
480 if (sseq && sseq->mainb == SEQ_DRAW_IMG_IMBUF) {
481 return (BKE_sequencer_mask_get(scene) != NULL);
487 int ED_space_sequencer_maskedit_poll(bContext *C)
489 SpaceSeq *sseq = CTX_wm_space_seq(C);
492 Scene *scene = CTX_data_scene(C);
493 return ED_space_sequencer_check_show_maskedit(sseq, scene);
499 /* are we displaying the seq output (not channels or histogram)*/
500 bool ED_space_sequencer_check_show_imbuf(SpaceSeq *sseq)
502 return (ELEM(sseq->view, SEQ_VIEW_PREVIEW, SEQ_VIEW_SEQUENCE_PREVIEW) &&
503 ELEM(sseq->mainb, SEQ_DRAW_SEQUENCE, SEQ_DRAW_IMG_IMBUF));
506 int seq_effect_find_selected(Scene *scene, Sequence *activeseq, int type, Sequence **selseq1, Sequence **selseq2, Sequence **selseq3, const char **error_str)
508 Editing *ed = BKE_sequencer_editing_get(scene, false);
509 Sequence *seq1 = NULL, *seq2 = NULL, *seq3 = NULL, *seq;
514 seq2 = BKE_sequencer_active_get(scene);
516 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
517 if (seq->flag & SELECT) {
518 if (seq->type == SEQ_TYPE_SOUND_RAM && BKE_sequence_effect_get_num_inputs(type) != 0) {
519 *error_str = N_("Cannot apply effects to audio sequence strips");
522 if ((seq != activeseq) && (seq != seq2)) {
523 if (seq2 == NULL) seq2 = seq;
524 else if (seq1 == NULL) seq1 = seq;
525 else if (seq3 == NULL) seq3 = seq;
527 *error_str = N_("Cannot apply effect to more than 3 sequence strips");
534 /* make sequence selection a little bit more intuitive
535 * for 3 strips: the last-strip should be sequence3 */
536 if (seq3 != NULL && seq2 != NULL) {
537 Sequence *tmp = seq2;
543 switch (BKE_sequence_effect_get_num_inputs(type)) {
545 *selseq1 = *selseq2 = *selseq3 = NULL;
546 return 1; /* succsess */
549 *error_str = N_("At least one selected sequence strip is needed");
552 if (seq1 == NULL) seq1 = seq2;
553 if (seq3 == NULL) seq3 = seq2;
556 if (seq1 == NULL || seq2 == NULL) {
557 *error_str = N_("2 selected sequence strips are needed");
560 if (seq3 == NULL) seq3 = seq2;
564 if (seq1 == NULL && seq2 == NULL && seq3 == NULL) {
565 *error_str = N_("TODO: in what cases does this happen?");
576 static Sequence *del_seq_find_replace_recurs(Scene *scene, Sequence *seq)
578 Sequence *seq1, *seq2, *seq3;
580 /* try to find a replacement input sequence, and flag for later deletion if
581 * no replacement can be found */
585 else if (!(seq->type & SEQ_TYPE_EFFECT))
586 return ((seq->flag & SELECT) ? NULL : seq);
587 else if (!(seq->flag & SELECT)) {
588 /* try to find replacement for effect inputs */
589 seq1 = del_seq_find_replace_recurs(scene, seq->seq1);
590 seq2 = del_seq_find_replace_recurs(scene, seq->seq2);
591 seq3 = del_seq_find_replace_recurs(scene, seq->seq3);
593 if (seq1 == seq->seq1 && seq2 == seq->seq2 && seq3 == seq->seq3) {
596 else if (seq1 || seq2 || seq3) {
597 seq->seq1 = (seq1) ? seq1 : (seq2) ? seq2 : seq3;
598 seq->seq2 = (seq2) ? seq2 : (seq1) ? seq1 : seq3;
599 seq->seq3 = (seq3) ? seq3 : (seq1) ? seq1 : seq2;
601 BKE_sequencer_update_changed_seq_and_deps(scene, seq, 1, 1);
604 seq->flag |= SELECT; /* mark for delete */
607 if (seq->flag & SELECT) {
608 if ((seq1 = del_seq_find_replace_recurs(scene, seq->seq1))) return seq1;
609 if ((seq2 = del_seq_find_replace_recurs(scene, seq->seq2))) return seq2;
610 if ((seq3 = del_seq_find_replace_recurs(scene, seq->seq3))) return seq3;
617 static void del_seq_clear_modifiers_recurs(Scene *scene, Sequence *deleting_sequence)
619 Editing *ed = BKE_sequencer_editing_get(scene, false);
620 Sequence *current_sequence;
622 SEQP_BEGIN(ed, current_sequence)
624 if (!(current_sequence->flag & SELECT) && current_sequence != deleting_sequence) {
625 SequenceModifierData *smd;
627 for (smd = current_sequence->modifiers.first; smd; smd = smd->next) {
628 if (smd->mask_sequence == deleting_sequence) {
629 smd->mask_sequence = NULL;
637 static void recurs_del_seq_flag(Scene *scene, ListBase *lb, short flag, short deleteall)
639 Sequence *seq, *seqn;
640 Sequence *last_seq = BKE_sequencer_active_get(scene);
645 if ((seq->flag & flag) || deleteall) {
646 BLI_remlink(lb, seq);
647 if (seq == last_seq) BKE_sequencer_active_set(scene, NULL);
648 if (seq->type == SEQ_TYPE_META) recurs_del_seq_flag(scene, &seq->seqbase, flag, 1);
649 BKE_sequence_free(scene, seq);
656 static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
659 Sequence *seqn = NULL;
660 bool skip_dup = false;
663 ts.start = seq->start;
664 ts.machine = seq->machine;
665 ts.startstill = seq->startstill;
666 ts.endstill = seq->endstill;
667 ts.startdisp = seq->startdisp;
668 ts.enddisp = seq->enddisp;
669 ts.startofs = seq->startofs;
670 ts.endofs = seq->endofs;
671 ts.anim_startofs = seq->anim_startofs;
672 ts.anim_endofs = seq->anim_endofs;
676 /* strips with extended stillfames before */
678 if ((seq->startstill) && (cutframe < seq->start)) {
679 /* don't do funny things with METAs ... */
680 if (seq->type == SEQ_TYPE_META) {
682 seq->startstill = seq->start - cutframe;
685 seq->start = cutframe - 1;
686 seq->startstill = cutframe - seq->startdisp - 1;
687 seq->anim_endofs += seq->len - 1;
692 else if ((cutframe >= seq->start) && (cutframe <= (seq->start + seq->len))) {
695 seq->anim_endofs += (seq->start + seq->len) - cutframe;
697 /* strips with extended stillframes after */
698 else if (((seq->start + seq->len) < cutframe) && (seq->endstill)) {
699 seq->endstill -= seq->enddisp - cutframe;
700 /* don't do funny things with METAs ... */
701 if (seq->type == SEQ_TYPE_META) {
706 BKE_sequence_reload_new_file(scene, seq, false);
707 BKE_sequence_calc(scene, seq);
710 /* Duplicate AFTER the first change */
711 seqn = BKE_sequence_dupli_recursive(scene, NULL, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
715 seqn->flag |= SELECT;
718 /* strips with extended stillframes before */
719 if ((seqn->startstill) && (cutframe == seqn->start + 1)) {
720 seqn->start = ts.start;
721 seqn->startstill = ts.start - cutframe;
722 seqn->anim_endofs = ts.anim_endofs;
723 seqn->endstill = ts.endstill;
727 else if ((cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len))) {
728 seqn->start = cutframe;
729 seqn->startstill = 0;
731 seqn->endofs = ts.endofs;
732 seqn->anim_startofs += cutframe - ts.start;
733 seqn->anim_endofs = ts.anim_endofs;
734 seqn->endstill = ts.endstill;
737 /* strips with extended stillframes after */
738 else if (((seqn->start + seqn->len) < cutframe) && (seqn->endstill)) {
739 seqn->start = cutframe;
741 seqn->anim_startofs += ts.len - 1;
742 seqn->endstill = ts.enddisp - cutframe - 1;
743 seqn->startstill = 0;
746 BKE_sequence_reload_new_file(scene, seqn, false);
747 BKE_sequence_calc(scene, seqn);
752 static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
755 Sequence *seqn = NULL;
756 bool skip_dup = false;
759 ts.start = seq->start;
760 ts.machine = seq->machine;
761 ts.startstill = seq->startstill;
762 ts.endstill = seq->endstill;
763 ts.startdisp = seq->startdisp;
764 ts.enddisp = seq->enddisp;
765 ts.startofs = seq->startofs;
766 ts.endofs = seq->endofs;
767 ts.anim_startofs = seq->anim_startofs;
768 ts.anim_endofs = seq->anim_endofs;
772 /* strips with extended stillfames before */
774 if ((seq->startstill) && (cutframe < seq->start)) {
775 /* don't do funny things with METAs ... */
776 if (seq->type == SEQ_TYPE_META) {
778 seq->startstill = seq->start - cutframe;
781 seq->start = cutframe - 1;
782 seq->startstill = cutframe - seq->startdisp - 1;
783 seq->endofs = seq->len - 1;
788 else if ((cutframe >= seq->start) && (cutframe <= (seq->start + seq->len))) {
789 seq->endofs = (seq->start + seq->len) - cutframe;
791 /* strips with extended stillframes after */
792 else if (((seq->start + seq->len) < cutframe) && (seq->endstill)) {
793 seq->endstill -= seq->enddisp - cutframe;
794 /* don't do funny things with METAs ... */
795 if (seq->type == SEQ_TYPE_META) {
800 BKE_sequence_calc(scene, seq);
803 /* Duplicate AFTER the first change */
804 seqn = BKE_sequence_dupli_recursive(scene, NULL, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
808 seqn->flag |= SELECT;
811 /* strips with extended stillframes before */
812 if ((seqn->startstill) && (cutframe == seqn->start + 1)) {
813 seqn->start = ts.start;
814 seqn->startstill = ts.start - cutframe;
815 seqn->endofs = ts.endofs;
816 seqn->endstill = ts.endstill;
820 else if ((cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len))) {
821 seqn->startstill = 0;
822 seqn->startofs = cutframe - ts.start;
823 seqn->endofs = ts.endofs;
824 seqn->endstill = ts.endstill;
827 /* strips with extended stillframes after */
828 else if (((seqn->start + seqn->len) < cutframe) && (seqn->endstill)) {
829 seqn->start = cutframe - ts.len + 1;
830 seqn->startofs = ts.len - 1;
831 seqn->endstill = ts.enddisp - cutframe - 1;
832 seqn->startstill = 0;
835 BKE_sequence_calc(scene, seqn);
841 /* like duplicate, but only duplicate and cut overlapping strips,
842 * strips to the left of the cutframe are ignored and strips to the right
843 * are moved to the end of slist
844 * we have to work on the same slist (not using a separate list), since
845 * otherwise dupli_seq can't check for duplicate names properly and
846 * may generate strips with the same name (which will mess up animdata)
849 static bool cut_seq_list(Scene *scene, ListBase *slist, int cutframe,
850 Sequence * (*cut_seq)(Scene *, Sequence *, int))
852 Sequence *seq, *seq_next_iter;
853 Sequence *seq_first_new = NULL;
857 while (seq && seq != seq_first_new) {
858 seq_next_iter = seq->next; /* we need this because we may remove seq */
860 if (seq->flag & SELECT) {
861 if (cutframe > seq->startdisp &&
862 cutframe < seq->enddisp)
864 Sequence *seqn = cut_seq(scene, seq, cutframe);
866 BLI_addtail(slist, seqn);
867 if (seq_first_new == NULL) {
868 seq_first_new = seqn;
872 else if (seq->enddisp <= cutframe) {
875 else if (seq->startdisp >= cutframe) {
877 BLI_remlink(slist, seq);
878 BLI_addtail(slist, seq);
880 if (seq_first_new == NULL) {
888 return (seq_first_new != NULL);
891 static bool sequence_offset_after_frame(Scene *scene, const int delta, const int cfra)
894 Editing *ed = BKE_sequencer_editing_get(scene, false);
897 /* all strips >= cfra are shifted */
899 if (ed == NULL) return 0;
901 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
902 if (seq->startdisp >= cfra) {
903 BKE_sequence_translate(scene, seq, delta);
904 BKE_sequence_calc(scene, seq);
912 static void UNUSED_FUNCTION(touch_seq_files) (Scene *scene)
915 Editing *ed = BKE_sequencer_editing_get(scene, false);
918 /* touch all strips with movies */
920 if (ed == NULL) return;
922 // XXX25 if (okee("Touch and print selected movies")==0) return;
928 if (seq->flag & SELECT) {
929 if (seq->type == SEQ_TYPE_MOVIE) {
930 if (seq->strip && seq->strip->stripdata) {
931 BLI_make_file_string(G.main->name, str, seq->strip->dir, seq->strip->stripdata->name);
932 BLI_file_touch(seq->name);
944 static void set_filter_seq(Scene *scene)
947 Editing *ed = BKE_sequencer_editing_get(scene, false);
950 if (ed == NULL) return;
952 if (okee("Set Deinterlace") == 0) return;
956 if (seq->flag & SELECT) {
957 if (seq->type == SEQ_TYPE_MOVIE) {
958 seq->flag |= SEQ_FILTERY;
959 BKE_sequence_reload_new_file(scene, seq, false);
960 BKE_sequence_calc(scene, seq);
969 static void UNUSED_FUNCTION(seq_remap_paths) (Scene *scene)
971 Sequence *seq, *last_seq = BKE_sequencer_active_get(scene);
972 Editing *ed = BKE_sequencer_editing_get(scene, false);
973 char from[FILE_MAX], to[FILE_MAX], stripped[FILE_MAX];
976 if (last_seq == NULL)
979 BLI_strncpy(from, last_seq->strip->dir, sizeof(from));
980 // XXX if (0 == sbutton(from, 0, sizeof(from)-1, "From: "))
983 BLI_strncpy(to, from, sizeof(to));
984 // XXX if (0 == sbutton(to, 0, sizeof(to)-1, "To: "))
987 if (strcmp(to, from) == 0)
992 if (seq->flag & SELECT) {
993 if (strncmp(seq->strip->dir, from, strlen(from)) == 0) {
994 printf("found %s\n", seq->strip->dir);
996 /* strip off the beginning */
998 BLI_strncpy(stripped, seq->strip->dir + strlen(from), FILE_MAX);
1001 BLI_snprintf(seq->strip->dir, sizeof(seq->strip->dir), "%s%s", to, stripped);
1002 printf("new %s\n", seq->strip->dir);
1011 static int sequencer_gap_remove_exec(bContext *C, wmOperator *op)
1013 Scene *scene = CTX_data_scene(C);
1015 int cfra, efra, sfra;
1016 bool first = false, done;
1017 bool do_all = RNA_boolean_get(op->ptr, "all");
1019 /* get first and last frame */
1020 boundbox_seq(scene, &rectf);
1021 sfra = (int)rectf.xmin;
1022 efra = (int)rectf.xmax;
1024 /* first check if the current frame has a gap already */
1025 for (cfra = CFRA; cfra >= sfra; cfra--) {
1026 if (BKE_sequencer_evaluate_frame(scene, cfra)) {
1032 for ( ; cfra < efra; cfra++) {
1033 /* first == 0 means there's still no strip to remove a gap for */
1034 if (first == false) {
1035 if (BKE_sequencer_evaluate_frame(scene, cfra) ) first = true;
1037 else if (BKE_sequencer_evaluate_frame(scene, cfra) == 0) {
1039 while (BKE_sequencer_evaluate_frame(scene, cfra) == 0) {
1040 done = sequence_offset_after_frame(scene, -1, cfra);
1041 if (done == false) break;
1043 if (done == false || do_all == false) break;
1047 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1049 return OPERATOR_FINISHED;
1054 void SEQUENCER_OT_gap_remove(struct wmOperatorType *ot)
1057 ot->name = "Remove Gaps";
1058 ot->idname = "SEQUENCER_OT_gap_remove";
1059 ot->description = "Remove gap at current frame to first strip at the right, independent of selection or locked state of strips";
1062 // ot->invoke = sequencer_snap_invoke;
1063 ot->exec = sequencer_gap_remove_exec;
1064 ot->poll = sequencer_edit_poll;
1067 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1069 RNA_def_boolean(ot->srna, "all", 0, "All Gaps", "Do all gaps to right of current frame");
1072 static int sequencer_gap_insert_exec(bContext *C, wmOperator *op)
1074 Scene *scene = CTX_data_scene(C);
1075 int frames = RNA_int_get(op->ptr, "frames");
1077 sequence_offset_after_frame(scene, frames, CFRA);
1079 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1081 return OPERATOR_FINISHED;
1085 void SEQUENCER_OT_gap_insert(struct wmOperatorType *ot)
1088 ot->name = "Insert Gaps";
1089 ot->idname = "SEQUENCER_OT_gap_insert";
1090 ot->description = "Insert gap at current frame to first strips at the right, independent of selection or locked state of strips";
1093 // ot->invoke = sequencer_snap_invoke;
1094 ot->exec = sequencer_gap_insert_exec;
1095 ot->poll = sequencer_edit_poll;
1098 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1100 RNA_def_int(ot->srna, "frames", 10, 0, INT_MAX, "Frames", "Frames to insert after current strip", 0, 1000);
1105 static int seq_get_snaplimit(View2D *v2d)
1107 /* fake mouse coords to get the snap value
1108 * a bit lazy but its only done once pre transform */
1109 float xmouse, ymouse, x;
1110 int mval[2] = {24, 0}; /* 24 screen px snap */
1112 UI_view2d_region_to_view(v2d, mval[0], mval[1], &xmouse, &ymouse);
1115 UI_view2d_region_to_view(v2d, mval[0], mval[1], &xmouse, &ymouse);
1116 return (int)(x - xmouse);
1120 /* Operator functions */
1121 int sequencer_edit_poll(bContext *C)
1123 return (BKE_sequencer_editing_get(CTX_data_scene(C), false) != NULL);
1127 int sequencer_strip_poll(bContext *C)
1130 return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) && (ed->act_seq != NULL));
1134 int sequencer_strip_has_path_poll(bContext *C)
1138 return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) && ((seq = ed->act_seq) != NULL) && (SEQ_HAS_PATH(seq)));
1141 int sequencer_view_poll(bContext *C)
1143 SpaceSeq *sseq = CTX_wm_space_seq(C);
1144 Editing *ed = BKE_sequencer_editing_get(CTX_data_scene(C), false);
1145 if (ed && sseq && (sseq->mainb == SEQ_DRAW_IMG_IMBUF))
1152 static int sequencer_snap_exec(bContext *C, wmOperator *op)
1154 Scene *scene = CTX_data_scene(C);
1156 Editing *ed = BKE_sequencer_editing_get(scene, false);
1160 snap_frame = RNA_int_get(op->ptr, "frame");
1162 /* also check metas */
1163 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
1164 if (seq->flag & SELECT && !(seq->depth == 0 && seq->flag & SEQ_LOCK) &&
1165 BKE_sequence_tx_test(seq))
1167 if ((seq->flag & (SEQ_LEFTSEL + SEQ_RIGHTSEL)) == 0) {
1168 /* simple but no anim update */
1169 /* seq->start = snap_frame-seq->startofs+seq->startstill; */
1171 BKE_sequence_translate(scene, seq, (snap_frame - seq->startofs + seq->startstill) - seq->start);
1174 if (seq->flag & SEQ_LEFTSEL) {
1175 BKE_sequence_tx_set_final_left(seq, snap_frame);
1177 else { /* SEQ_RIGHTSEL */
1178 BKE_sequence_tx_set_final_right(seq, snap_frame);
1180 BKE_sequence_tx_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL);
1182 BKE_sequence_calc(scene, seq);
1186 /* test for effects and overlap
1187 * don't use SEQP_BEGIN since that would be recursive */
1188 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
1189 if (seq->flag & SELECT && !(seq->depth == 0 && seq->flag & SEQ_LOCK)) {
1190 seq->flag &= ~SEQ_OVERLAP;
1191 if (BKE_sequence_test_overlap(ed->seqbasep, seq) ) {
1192 BKE_sequence_base_shuffle(ed->seqbasep, seq, scene);
1195 else if (seq->type & SEQ_TYPE_EFFECT) {
1196 if (seq->seq1 && (seq->seq1->flag & SELECT))
1197 BKE_sequence_calc(scene, seq);
1198 else if (seq->seq2 && (seq->seq2->flag & SELECT))
1199 BKE_sequence_calc(scene, seq);
1200 else if (seq->seq3 && (seq->seq3->flag & SELECT))
1201 BKE_sequence_calc(scene, seq);
1206 BKE_sequencer_sort(scene);
1208 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1210 return OPERATOR_FINISHED;
1213 static int sequencer_snap_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
1215 Scene *scene = CTX_data_scene(C);
1221 RNA_int_set(op->ptr, "frame", snap_frame);
1222 return sequencer_snap_exec(C, op);
1225 void SEQUENCER_OT_snap(struct wmOperatorType *ot)
1228 ot->name = "Snap Strips";
1229 ot->idname = "SEQUENCER_OT_snap";
1230 ot->description = "Frame where selected strips will be snapped";
1233 ot->invoke = sequencer_snap_invoke;
1234 ot->exec = sequencer_snap_exec;
1235 ot->poll = sequencer_edit_poll;
1238 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1240 RNA_def_int(ot->srna, "frame", 0, INT_MIN, INT_MAX, "Frame", "Frame where selected strips will be snapped", INT_MIN, INT_MAX);
1244 static int sequencer_mute_exec(bContext *C, wmOperator *op)
1246 Scene *scene = CTX_data_scene(C);
1247 Editing *ed = BKE_sequencer_editing_get(scene, false);
1251 selected = !RNA_boolean_get(op->ptr, "unselected");
1253 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
1254 if ((seq->flag & SEQ_LOCK) == 0) {
1255 if (selected) { /* mute unselected */
1256 if (seq->flag & SELECT) {
1257 seq->flag |= SEQ_MUTE;
1258 BKE_sequence_invalidate_dependent(scene, seq);
1262 if ((seq->flag & SELECT) == 0) {
1263 seq->flag |= SEQ_MUTE;
1264 BKE_sequence_invalidate_dependent(scene, seq);
1270 BKE_sequencer_update_muting(ed);
1271 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1273 return OPERATOR_FINISHED;
1276 void SEQUENCER_OT_mute(struct wmOperatorType *ot)
1279 ot->name = "Mute Strips";
1280 ot->idname = "SEQUENCER_OT_mute";
1281 ot->description = "Mute selected strips";
1284 ot->exec = sequencer_mute_exec;
1285 ot->poll = sequencer_edit_poll;
1288 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1290 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Mute unselected rather than selected strips");
1294 /* unmute operator */
1295 static int sequencer_unmute_exec(bContext *C, wmOperator *op)
1297 Scene *scene = CTX_data_scene(C);
1298 Editing *ed = BKE_sequencer_editing_get(scene, false);
1302 selected = !RNA_boolean_get(op->ptr, "unselected");
1304 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
1305 if ((seq->flag & SEQ_LOCK) == 0) {
1306 if (selected) { /* unmute unselected */
1307 if (seq->flag & SELECT) {
1308 seq->flag &= ~SEQ_MUTE;
1309 BKE_sequence_invalidate_dependent(scene, seq);
1313 if ((seq->flag & SELECT) == 0) {
1314 seq->flag &= ~SEQ_MUTE;
1315 BKE_sequence_invalidate_dependent(scene, seq);
1321 BKE_sequencer_update_muting(ed);
1322 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1324 return OPERATOR_FINISHED;
1327 void SEQUENCER_OT_unmute(struct wmOperatorType *ot)
1330 ot->name = "Un-Mute Strips";
1331 ot->idname = "SEQUENCER_OT_unmute";
1332 ot->description = "Un-Mute unselected rather than selected strips";
1335 ot->exec = sequencer_unmute_exec;
1336 ot->poll = sequencer_edit_poll;
1339 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1341 RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "UnMute unselected rather than selected strips");
1346 static int sequencer_lock_exec(bContext *C, wmOperator *UNUSED(op))
1348 Scene *scene = CTX_data_scene(C);
1349 Editing *ed = BKE_sequencer_editing_get(scene, false);
1352 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
1353 if (seq->flag & SELECT) {
1354 seq->flag |= SEQ_LOCK;
1358 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1360 return OPERATOR_FINISHED;
1363 void SEQUENCER_OT_lock(struct wmOperatorType *ot)
1366 ot->name = "Lock Strips";
1367 ot->idname = "SEQUENCER_OT_lock";
1368 ot->description = "Lock the active strip so that it can't be transformed";
1371 ot->exec = sequencer_lock_exec;
1372 ot->poll = sequencer_edit_poll;
1375 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1378 /* unlock operator */
1379 static int sequencer_unlock_exec(bContext *C, wmOperator *UNUSED(op))
1381 Scene *scene = CTX_data_scene(C);
1382 Editing *ed = BKE_sequencer_editing_get(scene, false);
1385 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
1386 if (seq->flag & SELECT) {
1387 seq->flag &= ~SEQ_LOCK;
1391 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1393 return OPERATOR_FINISHED;
1396 void SEQUENCER_OT_unlock(struct wmOperatorType *ot)
1399 ot->name = "UnLock Strips";
1400 ot->idname = "SEQUENCER_OT_unlock";
1401 ot->description = "Unlock the active strip so that it can't be transformed";
1404 ot->exec = sequencer_unlock_exec;
1405 ot->poll = sequencer_edit_poll;
1408 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1411 /* reload operator */
1412 static int sequencer_reload_exec(bContext *C, wmOperator *op)
1414 Scene *scene = CTX_data_scene(C);
1415 Editing *ed = BKE_sequencer_editing_get(scene, false);
1417 const bool adjust_length = RNA_boolean_get(op->ptr, "adjust_length");
1419 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
1420 if (seq->flag & SELECT) {
1421 BKE_sequencer_update_changed_seq_and_deps(scene, seq, 0, 1);
1422 BKE_sequence_reload_new_file(scene, seq, !adjust_length);
1424 if (adjust_length) {
1425 if (BKE_sequence_test_overlap(ed->seqbasep, seq))
1426 BKE_sequence_base_shuffle(ed->seqbasep, seq, scene);
1431 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1433 return OPERATOR_FINISHED;
1436 void SEQUENCER_OT_reload(struct wmOperatorType *ot)
1441 ot->name = "Reload Strips";
1442 ot->idname = "SEQUENCER_OT_reload";
1443 ot->description = "Reload strips in the sequencer";
1446 ot->exec = sequencer_reload_exec;
1447 ot->poll = sequencer_edit_poll;
1450 ot->flag = OPTYPE_REGISTER; /* no undo, the data changed is stored outside 'main' */
1452 prop = RNA_def_boolean(ot->srna, "adjust_length", 0, "Adjust Length",
1453 "Adjust length of strips to their data length");
1454 RNA_def_property_flag(prop, PROP_SKIP_SAVE);
1457 /* reload operator */
1458 static int sequencer_refresh_all_exec(bContext *C, wmOperator *UNUSED(op))
1460 Scene *scene = CTX_data_scene(C);
1461 Editing *ed = BKE_sequencer_editing_get(scene, false);
1463 BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
1465 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1467 return OPERATOR_FINISHED;
1470 void SEQUENCER_OT_refresh_all(struct wmOperatorType *ot)
1473 ot->name = "Refresh Sequencer";
1474 ot->idname = "SEQUENCER_OT_refresh_all";
1475 ot->description = "Refresh the sequencer editor";
1478 ot->exec = sequencer_refresh_all_exec;
1479 ot->poll = sequencer_edit_poll;
1482 static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op)
1484 Scene *scene = CTX_data_scene(C);
1485 Sequence *seq1, *seq2, *seq3, *last_seq = BKE_sequencer_active_get(scene);
1486 const char *error_msg;
1488 if (!seq_effect_find_selected(scene, last_seq, last_seq->type, &seq1, &seq2, &seq3, &error_msg)) {
1489 BKE_report(op->reports, RPT_ERROR, error_msg);
1490 return OPERATOR_CANCELLED;
1492 /* see reassigning would create a cycle */
1493 if (seq_is_predecessor(seq1, last_seq) ||
1494 seq_is_predecessor(seq2, last_seq) ||
1495 seq_is_predecessor(seq3, last_seq))
1497 BKE_report(op->reports, RPT_ERROR, "Cannot reassign inputs: no cycles allowed");
1498 return OPERATOR_CANCELLED;
1501 last_seq->seq1 = seq1;
1502 last_seq->seq2 = seq2;
1503 last_seq->seq3 = seq3;
1505 BKE_sequencer_update_changed_seq_and_deps(scene, last_seq, 1, 1);
1507 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1509 return OPERATOR_FINISHED;
1512 static int sequencer_effect_poll(bContext *C)
1514 Scene *scene = CTX_data_scene(C);
1515 Editing *ed = BKE_sequencer_editing_get(scene, false);
1518 Sequence *last_seq = BKE_sequencer_active_get(scene);
1519 if (last_seq && (last_seq->type & SEQ_TYPE_EFFECT)) {
1527 void SEQUENCER_OT_reassign_inputs(struct wmOperatorType *ot)
1530 ot->name = "Reassign Inputs";
1531 ot->idname = "SEQUENCER_OT_reassign_inputs";
1532 ot->description = "Reassign the inputs for the effect strip";
1535 ot->exec = sequencer_reassign_inputs_exec;
1536 ot->poll = sequencer_effect_poll;
1539 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1543 static int sequencer_swap_inputs_exec(bContext *C, wmOperator *op)
1545 Scene *scene = CTX_data_scene(C);
1546 Sequence *seq, *last_seq = BKE_sequencer_active_get(scene);
1548 if (last_seq->seq1 == NULL || last_seq->seq2 == NULL) {
1549 BKE_report(op->reports, RPT_ERROR, "No valid inputs to swap");
1550 return OPERATOR_CANCELLED;
1553 seq = last_seq->seq1;
1554 last_seq->seq1 = last_seq->seq2;
1555 last_seq->seq2 = seq;
1557 BKE_sequencer_update_changed_seq_and_deps(scene, last_seq, 1, 1);
1559 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1561 return OPERATOR_FINISHED;
1563 void SEQUENCER_OT_swap_inputs(struct wmOperatorType *ot)
1566 ot->name = "Swap Inputs";
1567 ot->idname = "SEQUENCER_OT_swap_inputs";
1568 ot->description = "Swap the first two inputs for the effect strip";
1571 ot->exec = sequencer_swap_inputs_exec;
1572 ot->poll = sequencer_effect_poll;
1575 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1580 static EnumPropertyItem prop_cut_types[] = {
1581 {SEQ_CUT_SOFT, "SOFT", 0, "Soft", ""},
1582 {SEQ_CUT_HARD, "HARD", 0, "Hard", ""},
1583 {0, NULL, 0, NULL, NULL}
1586 static int sequencer_cut_exec(bContext *C, wmOperator *op)
1588 Scene *scene = CTX_data_scene(C);
1589 Editing *ed = BKE_sequencer_editing_get(scene, false);
1590 int cut_side, cut_hard, cut_frame;
1594 cut_frame = RNA_int_get(op->ptr, "frame");
1595 cut_hard = RNA_enum_get(op->ptr, "type");
1596 cut_side = RNA_enum_get(op->ptr, "side");
1598 if (cut_hard == SEQ_CUT_HARD) {
1599 changed = cut_seq_list(scene, ed->seqbasep, cut_frame, cut_seq_hard);
1602 changed = cut_seq_list(scene, ed->seqbasep, cut_frame, cut_seq_soft);
1605 if (changed) { /* got new strips ? */
1608 if (cut_side != SEQ_SIDE_BOTH) {
1609 SEQP_BEGIN (ed, seq)
1611 if (cut_side == SEQ_SIDE_LEFT) {
1612 if (seq->startdisp >= cut_frame) {
1613 seq->flag &= ~SEQ_ALLSEL;
1617 if (seq->enddisp <= cut_frame) {
1618 seq->flag &= ~SEQ_ALLSEL;
1625 SEQP_BEGIN (ed, seq)
1627 if (seq->seq1 || seq->seq2 || seq->seq3) {
1628 BKE_sequence_calc(scene, seq);
1634 BKE_sequencer_sort(scene);
1638 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1639 return OPERATOR_FINISHED;
1642 return OPERATOR_CANCELLED;
1647 static int sequencer_cut_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1649 Scene *scene = CTX_data_scene(C);
1650 View2D *v2d = UI_view2d_fromcontext(C);
1652 int cut_side = SEQ_SIDE_BOTH;
1653 int cut_frame = CFRA;
1655 if (ED_operator_sequencer_active(C) && v2d)
1656 cut_side = mouse_frame_side(v2d, event->mval[0], cut_frame);
1658 RNA_int_set(op->ptr, "frame", cut_frame);
1659 RNA_enum_set(op->ptr, "side", cut_side);
1660 /*RNA_enum_set(op->ptr, "type", cut_hard); */ /*This type is set from the key shortcut */
1662 return sequencer_cut_exec(C, op);
1666 void SEQUENCER_OT_cut(struct wmOperatorType *ot)
1669 ot->name = "Cut Strips";
1670 ot->idname = "SEQUENCER_OT_cut";
1671 ot->description = "Cut the selected strips";
1674 ot->invoke = sequencer_cut_invoke;
1675 ot->exec = sequencer_cut_exec;
1676 ot->poll = sequencer_edit_poll;
1679 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1681 RNA_def_int(ot->srna, "frame", 0, INT_MIN, INT_MAX, "Frame", "Frame where selected strips will be cut", INT_MIN, INT_MAX);
1682 RNA_def_enum(ot->srna, "type", prop_cut_types, SEQ_CUT_SOFT, "Type", "The type of cut operation to perform on strips");
1683 RNA_def_enum(ot->srna, "side", prop_side_types, SEQ_SIDE_BOTH, "Side", "The side that remains selected after cutting");
1686 /* duplicate operator */
1687 static int apply_unique_name_cb(Sequence *seq, void *arg_pt)
1689 Scene *scene = (Scene *)arg_pt;
1690 char name[sizeof(seq->name) - 2];
1692 BLI_strncpy_utf8(name, seq->name + 2, sizeof(name));
1693 BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seq);
1694 BKE_sequencer_dupe_animdata(scene, name, seq->name + 2);
1699 static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
1701 Scene *scene = CTX_data_scene(C);
1702 Editing *ed = BKE_sequencer_editing_get(scene, false);
1704 ListBase nseqbase = {NULL, NULL};
1707 return OPERATOR_CANCELLED;
1709 BKE_sequence_base_dupli_recursive(scene, NULL, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT);
1711 if (nseqbase.first) {
1712 Sequence *seq = nseqbase.first;
1713 /* rely on the nseqbase list being added at the end */
1714 BLI_movelisttolist(ed->seqbasep, &nseqbase);
1716 for (; seq; seq = seq->next)
1717 BKE_sequencer_recursive_apply(seq, apply_unique_name_cb, scene);
1719 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1720 return OPERATOR_FINISHED;
1723 return OPERATOR_CANCELLED;
1726 void SEQUENCER_OT_duplicate(wmOperatorType *ot)
1729 ot->name = "Duplicate Strips";
1730 ot->idname = "SEQUENCER_OT_duplicate";
1731 ot->description = "Duplicate the selected strips";
1734 ot->exec = sequencer_add_duplicate_exec;
1735 ot->poll = ED_operator_sequencer_active;
1738 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1740 /* to give to transform */
1741 RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
1744 /* delete operator */
1745 static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
1747 Scene *scene = CTX_data_scene(C);
1748 Editing *ed = BKE_sequencer_editing_get(scene, false);
1751 bool nothingSelected = true;
1753 seq = BKE_sequencer_active_get(scene);
1754 if (seq && seq->flag & SELECT) { /* avoid a loop since this is likely to be selected */
1755 nothingSelected = false;
1758 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
1759 if (seq->flag & SELECT) {
1760 nothingSelected = false;
1766 if (nothingSelected)
1767 return OPERATOR_FINISHED;
1769 /* for effects and modifiers, try to find a replacement input */
1770 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
1771 if (!(seq->flag & SELECT)) {
1772 if ((seq->type & SEQ_TYPE_EFFECT)) {
1773 del_seq_find_replace_recurs(scene, seq);
1777 del_seq_clear_modifiers_recurs(scene, seq);
1781 /* delete all selected strips */
1782 recurs_del_seq_flag(scene, ed->seqbasep, SELECT, 0);
1784 /* updates lengths etc */
1785 seq = ed->seqbasep->first;
1787 BKE_sequence_calc(scene, seq);
1791 /* free parent metas */
1792 ms = ed->metastack.last;
1794 BKE_sequence_calc(scene, ms->parseq);
1798 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1800 return OPERATOR_FINISHED;
1803 static int sequencer_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1805 ARegion *ar = CTX_wm_region(C);
1807 if (ar->regiontype == RGN_TYPE_WINDOW) {
1808 /* bounding box of 30 pixels is used for markers shortcuts,
1809 * prevent conflict with markers shortcuts here
1811 if (event->mval[1] <= 30)
1812 return OPERATOR_PASS_THROUGH;
1815 return WM_operator_confirm(C, op, event);
1818 void SEQUENCER_OT_delete(wmOperatorType *ot)
1822 ot->name = "Erase Strips";
1823 ot->idname = "SEQUENCER_OT_delete";
1824 ot->description = "Erase selected strips from the sequencer";
1827 ot->invoke = sequencer_delete_invoke;
1828 ot->exec = sequencer_delete_exec;
1829 ot->poll = sequencer_edit_poll;
1832 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1836 /* offset clear operator */
1837 static int sequencer_offset_clear_exec(bContext *C, wmOperator *UNUSED(op))
1839 Scene *scene = CTX_data_scene(C);
1840 Editing *ed = BKE_sequencer_editing_get(scene, false);
1843 /* for effects, try to find a replacement input */
1844 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
1845 if ((seq->type & SEQ_TYPE_EFFECT) == 0 && (seq->flag & SELECT)) {
1846 seq->startofs = seq->endofs = seq->startstill = seq->endstill = 0;
1850 /* updates lengths etc */
1851 seq = ed->seqbasep->first;
1853 BKE_sequence_calc(scene, seq);
1857 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
1858 if ((seq->type & SEQ_TYPE_EFFECT) == 0 && (seq->flag & SELECT)) {
1859 if (BKE_sequence_test_overlap(ed->seqbasep, seq)) {
1860 BKE_sequence_base_shuffle(ed->seqbasep, seq, scene);
1865 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1867 return OPERATOR_FINISHED;
1871 void SEQUENCER_OT_offset_clear(wmOperatorType *ot)
1875 ot->name = "Clear Strip Offset";
1876 ot->idname = "SEQUENCER_OT_offset_clear";
1877 ot->description = "Clear strip offsets from the start and end frames";
1880 ot->exec = sequencer_offset_clear_exec;
1881 ot->poll = sequencer_edit_poll;
1884 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1888 /* separate_images operator */
1889 static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
1891 Scene *scene = CTX_data_scene(C);
1892 Editing *ed = BKE_sequencer_editing_get(scene, false);
1894 Sequence *seq, *seq_new;
1896 StripElem *se, *se_new;
1897 int start_ofs, cfra, frame_end;
1898 int step = RNA_int_get(op->ptr, "length");
1900 seq = ed->seqbasep->first; /* poll checks this is valid */
1903 if ((seq->flag & SELECT) && (seq->type == SEQ_TYPE_IMAGE) && (seq->len > 1)) {
1906 /* remove seq so overlap tests don't conflict,
1907 * see seq_free_sequence below for the real free'ing */
1908 BLI_remlink(ed->seqbasep, seq);
1909 /* if (seq->ipo) seq->ipo->id.us--; */
1910 /* XXX, remove fcurve and assign to split image strips */
1912 start_ofs = cfra = BKE_sequence_tx_get_final_left(seq, false);
1913 frame_end = BKE_sequence_tx_get_final_right(seq, false);
1915 while (cfra < frame_end) {
1917 se = BKE_sequencer_give_stripelem(seq, cfra);
1919 seq_new = BKE_sequence_dupli_recursive(scene, scene, seq, SEQ_DUPE_UNIQUE_NAME);
1920 BLI_addtail(ed->seqbasep, seq_new);
1922 seq_new->start = start_ofs;
1923 seq_new->type = SEQ_TYPE_IMAGE;
1925 seq_new->endstill = step - 1;
1928 strip_new = seq_new->strip;
1932 se_new = strip_new->stripdata;
1933 BLI_strncpy(se_new->name, se->name, sizeof(se_new->name));
1934 BKE_sequence_calc(scene, seq_new);
1937 seq_new->flag &= ~SEQ_OVERLAP;
1938 if (BKE_sequence_test_overlap(ed->seqbasep, seq_new)) {
1939 BKE_sequence_base_shuffle(ed->seqbasep, seq_new, scene);
1943 /* XXX, COPY FCURVES */
1949 seq_next = seq->next;
1950 BKE_sequence_free(scene, seq);
1959 BKE_sequencer_sort(scene);
1961 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
1963 return OPERATOR_FINISHED;
1967 void SEQUENCER_OT_images_separate(wmOperatorType *ot)
1970 ot->name = "Separate Images";
1971 ot->idname = "SEQUENCER_OT_images_separate";
1972 ot->description = "On image sequence strips, it returns a strip for each image";
1975 ot->exec = sequencer_separate_images_exec;
1976 ot->invoke = WM_operator_props_popup;
1977 ot->poll = sequencer_edit_poll;
1980 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
1982 RNA_def_int(ot->srna, "length", 1, 1, INT_MAX, "Length", "Length of each frame", 1, 1000);
1986 /* META Operators */
1988 /* separate_meta_toggle operator */
1989 static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
1991 Scene *scene = CTX_data_scene(C);
1992 Editing *ed = BKE_sequencer_editing_get(scene, false);
1993 Sequence *last_seq = BKE_sequencer_active_get(scene);
1996 if (last_seq && last_seq->type == SEQ_TYPE_META && last_seq->flag & SELECT) {
1997 /* Enter Metastrip */
1998 ms = MEM_mallocN(sizeof(MetaStack), "metastack");
1999 BLI_addtail(&ed->metastack, ms);
2000 ms->parseq = last_seq;
2001 ms->oldbasep = ed->seqbasep;
2003 ed->seqbasep = &last_seq->seqbase;
2005 BKE_sequencer_active_set(scene, NULL);
2009 /* Exit Metastrip (if possible) */
2013 if (BLI_listbase_is_empty(&ed->metastack))
2014 return OPERATOR_CANCELLED;
2016 ms = ed->metastack.last;
2017 BLI_remlink(&ed->metastack, ms);
2019 ed->seqbasep = ms->oldbasep;
2021 /* recalc all: the meta can have effects connected to it */
2022 for (seq = ed->seqbasep->first; seq; seq = seq->next)
2023 BKE_sequence_calc(scene, seq);
2025 if (BKE_sequence_test_overlap(ed->seqbasep, ms->parseq))
2026 BKE_sequence_base_shuffle(ed->seqbasep, ms->parseq, scene);
2028 BKE_sequencer_active_set(scene, ms->parseq);
2030 ms->parseq->flag |= SELECT;
2031 recurs_sel_seq(ms->parseq);
2037 BKE_sequencer_update_muting(ed);
2038 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
2040 return OPERATOR_FINISHED;
2043 void SEQUENCER_OT_meta_toggle(wmOperatorType *ot)
2046 ot->name = "Toggle Meta Strip";
2047 ot->idname = "SEQUENCER_OT_meta_toggle";
2048 ot->description = "Toggle a metastrip (to edit enclosed strips)";
2051 ot->exec = sequencer_meta_toggle_exec;
2052 ot->poll = sequencer_edit_poll;
2055 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2059 /* separate_meta_make operator */
2060 static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
2062 Scene *scene = CTX_data_scene(C);
2063 Editing *ed = BKE_sequencer_editing_get(scene, false);
2065 Sequence *seq, *seqm, *next, *last_seq = BKE_sequencer_active_get(scene);
2066 int channel_max = 1;
2068 if (BKE_sequence_base_isolated_sel_check(ed->seqbasep) == false) {
2069 BKE_report(op->reports, RPT_ERROR, "Please select all related strips");
2070 return OPERATOR_CANCELLED;
2073 /* remove all selected from main list, and put in meta */
2075 seqm = BKE_sequence_alloc(ed->seqbasep, 1, 1); /* channel number set later */
2076 strcpy(seqm->name + 2, "MetaStrip");
2077 seqm->type = SEQ_TYPE_META;
2078 seqm->flag = SELECT;
2080 seq = ed->seqbasep->first;
2083 if (seq != seqm && (seq->flag & SELECT)) {
2084 channel_max = max_ii(seq->machine, channel_max);
2085 BLI_remlink(ed->seqbasep, seq);
2086 BLI_addtail(&seqm->seqbase, seq);
2090 seqm->machine = last_seq ? last_seq->machine : channel_max;
2091 BKE_sequence_calc(scene, seqm);
2093 seqm->strip = MEM_callocN(sizeof(Strip), "metastrip");
2094 seqm->strip->us = 1;
2096 BKE_sequencer_active_set(scene, seqm);
2098 if (BKE_sequence_test_overlap(ed->seqbasep, seqm) ) BKE_sequence_base_shuffle(ed->seqbasep, seqm, scene);
2100 BKE_sequencer_update_muting(ed);
2102 BKE_sequence_base_unique_name_recursive(&scene->ed->seqbase, seqm);
2104 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
2106 return OPERATOR_FINISHED;
2109 void SEQUENCER_OT_meta_make(wmOperatorType *ot)
2112 ot->name = "Make Meta Strip";
2113 ot->idname = "SEQUENCER_OT_meta_make";
2114 ot->description = "Group selected strips into a metastrip";
2117 ot->exec = sequencer_meta_make_exec;
2118 ot->poll = sequencer_edit_poll;
2121 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2125 static int seq_depends_on_meta(Sequence *seq, Sequence *seqm)
2127 if (seq == seqm) return 1;
2128 else if (seq->seq1 && seq_depends_on_meta(seq->seq1, seqm)) return 1;
2129 else if (seq->seq2 && seq_depends_on_meta(seq->seq2, seqm)) return 1;
2130 else if (seq->seq3 && seq_depends_on_meta(seq->seq3, seqm)) return 1;
2134 /* separate_meta_make operator */
2135 static int sequencer_meta_separate_exec(bContext *C, wmOperator *UNUSED(op))
2137 Scene *scene = CTX_data_scene(C);
2138 Editing *ed = BKE_sequencer_editing_get(scene, false);
2140 Sequence *seq, *last_seq = BKE_sequencer_active_get(scene); /* last_seq checks (ed == NULL) */
2142 if (last_seq == NULL || last_seq->type != SEQ_TYPE_META)
2143 return OPERATOR_CANCELLED;
2145 BLI_movelisttolist(ed->seqbasep, &last_seq->seqbase);
2147 BLI_listbase_clear(&last_seq->seqbase);
2149 BLI_remlink(ed->seqbasep, last_seq);
2150 BKE_sequence_free(scene, last_seq);
2152 /* emtpy meta strip, delete all effects depending on it */
2153 for (seq = ed->seqbasep->first; seq; seq = seq->next)
2154 if ((seq->type & SEQ_TYPE_EFFECT) && seq_depends_on_meta(seq, last_seq))
2155 seq->flag |= SEQ_FLAG_DELETE;
2157 recurs_del_seq_flag(scene, ed->seqbasep, SEQ_FLAG_DELETE, 0);
2159 /* test for effects and overlap
2160 * don't use SEQP_BEGIN since that would be recursive */
2161 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
2162 if (seq->flag & SELECT) {
2163 seq->flag &= ~SEQ_OVERLAP;
2164 if (BKE_sequence_test_overlap(ed->seqbasep, seq)) {
2165 BKE_sequence_base_shuffle(ed->seqbasep, seq, scene);
2170 BKE_sequencer_sort(scene);
2171 BKE_sequencer_update_muting(ed);
2173 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
2175 return OPERATOR_FINISHED;
2178 void SEQUENCER_OT_meta_separate(wmOperatorType *ot)
2181 ot->name = "UnMeta Strip";
2182 ot->idname = "SEQUENCER_OT_meta_separate";
2183 ot->description = "Put the contents of a metastrip back in the sequencer";
2186 ot->exec = sequencer_meta_separate_exec;
2187 ot->poll = sequencer_edit_poll;
2190 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2193 /* view_all operator */
2194 static int sequencer_view_all_exec(bContext *C, wmOperator *op)
2196 ARegion *ar = CTX_wm_region(C);
2197 View2D *v2d = UI_view2d_fromcontext(C);
2198 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
2200 UI_view2d_smooth_view(C, ar, &v2d->tot, smooth_viewtx);
2201 return OPERATOR_FINISHED;
2204 void SEQUENCER_OT_view_all(wmOperatorType *ot)
2207 ot->name = "View All";
2208 ot->idname = "SEQUENCER_OT_view_all";
2209 ot->description = "View all the strips in the sequencer";
2212 ot->exec = sequencer_view_all_exec;
2213 ot->poll = ED_operator_sequencer_active;
2216 ot->flag = OPTYPE_REGISTER;
2219 /* view_all operator */
2220 static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op))
2222 bScreen *sc = CTX_wm_screen(C);
2223 ScrArea *area = CTX_wm_area(C);
2225 ARegion *ar = CTX_wm_region(C);
2226 SpaceSeq *sseq = area->spacedata.first;
2227 Scene *scene = CTX_data_scene(C);
2229 View2D *v2d = UI_view2d_fromcontext(C);
2231 v2d->cur = v2d->tot;
2232 UI_view2d_curRect_validate(v2d);
2233 UI_view2d_sync(sc, area, v2d, V2D_LOCK_COPY);
2236 /* Like zooming on an image view */
2238 int width, height, imgwidth, imgheight;
2243 seq_reset_imageofs(sseq);
2245 imgwidth = (scene->r.size * scene->r.xsch) / 100;
2246 imgheight = (scene->r.size * scene->r.ysch) / 100;
2248 /* Apply aspect, dosnt need to be that accurate */
2249 imgwidth = (int)(imgwidth * (scene->r.xasp / scene->r.yasp));
2251 if (((imgwidth >= width) || (imgheight >= height)) &&
2252 ((width > 0) && (height > 0)))
2254 /* Find the zoom value that will fit the image in the image space */
2255 zoomX = ((float)width) / ((float)imgwidth);
2256 zoomY = ((float)height) / ((float)imgheight);
2257 sseq->zoom = (zoomX < zoomY) ? zoomX : zoomY;
2259 sseq->zoom = 1.0f / power_of_2(1 / min_ff(zoomX, zoomY));
2266 ED_area_tag_redraw(CTX_wm_area(C));
2267 return OPERATOR_FINISHED;
2270 void SEQUENCER_OT_view_all_preview(wmOperatorType *ot)
2273 ot->name = "View All";
2274 ot->idname = "SEQUENCER_OT_view_all_preview";
2275 ot->description = "Zoom preview to fit in the area";
2278 ot->exec = sequencer_view_all_preview_exec;
2279 ot->poll = ED_operator_sequencer_active;
2282 ot->flag = OPTYPE_REGISTER;
2286 static int sequencer_view_zoom_ratio_exec(bContext *C, wmOperator *op)
2288 RenderData *rd = &CTX_data_scene(C)->r;
2289 View2D *v2d = UI_view2d_fromcontext(C);
2291 float ratio = RNA_float_get(op->ptr, "ratio");
2293 float winx = (int)(rd->size * rd->xsch) / 100;
2294 float winy = (int)(rd->size * rd->ysch) / 100;
2296 float facx = BLI_rcti_size_x(&v2d->mask) / winx;
2297 float facy = BLI_rcti_size_y(&v2d->mask) / winy;
2299 BLI_rctf_resize(&v2d->cur, floorf(winx * facx / ratio + 0.5f), floorf(winy * facy / ratio + 0.5f));
2301 ED_region_tag_redraw(CTX_wm_region(C));
2303 return OPERATOR_FINISHED;
2306 void SEQUENCER_OT_view_zoom_ratio(wmOperatorType *ot)
2309 ot->name = "Sequencer View Zoom Ratio";
2310 ot->idname = "SEQUENCER_OT_view_zoom_ratio";
2311 ot->description = "Change zoom ratio of sequencer preview";
2314 ot->exec = sequencer_view_zoom_ratio_exec;
2315 ot->poll = ED_operator_sequencer_active;
2318 RNA_def_float(ot->srna, "ratio", 1.0f, -FLT_MAX, FLT_MAX,
2319 "Ratio", "Zoom ratio, 1.0 is 1:1, higher is zoomed in, lower is zoomed out", -FLT_MAX, FLT_MAX);
2324 static EnumPropertyItem view_type_items[] = {
2325 {SEQ_VIEW_SEQUENCE, "SEQUENCER", ICON_SEQ_SEQUENCER, "Sequencer", ""},
2326 {SEQ_VIEW_PREVIEW, "PREVIEW", ICON_SEQ_PREVIEW, "Image Preview", ""},
2327 {SEQ_VIEW_SEQUENCE_PREVIEW, "SEQUENCER_PREVIEW", ICON_SEQ_SEQUENCER, "Sequencer and Image Preview", ""},
2328 {0, NULL, 0, NULL, NULL}
2332 /* view_all operator */
2333 static int sequencer_view_toggle_exec(bContext *C, wmOperator *UNUSED(op))
2335 SpaceSeq *sseq = (SpaceSeq *)CTX_wm_space_data(C);
2338 if (sseq->view > SEQ_VIEW_SEQUENCE_PREVIEW) sseq->view = SEQ_VIEW_SEQUENCE;
2340 ED_area_tag_refresh(CTX_wm_area(C));
2342 return OPERATOR_FINISHED;
2345 void SEQUENCER_OT_view_toggle(wmOperatorType *ot)
2348 ot->name = "View Toggle";
2349 ot->idname = "SEQUENCER_OT_view_toggle";
2350 ot->description = "Toggle between sequencer views (sequence, preview, both)";
2353 ot->exec = sequencer_view_toggle_exec;
2354 ot->poll = ED_operator_sequencer_active;
2357 ot->flag = OPTYPE_REGISTER;
2361 /* view_selected operator */
2362 static int sequencer_view_selected_exec(bContext *C, wmOperator *op)
2364 Scene *scene = CTX_data_scene(C);
2365 View2D *v2d = UI_view2d_fromcontext(C);
2366 ARegion *ar = CTX_wm_region(C);
2367 Editing *ed = BKE_sequencer_editing_get(scene, false);
2368 Sequence *last_seq = BKE_sequencer_active_get(scene);
2370 rctf cur_new = v2d->cur;
2372 int xmin = MAXFRAME * 2;
2373 int xmax = -MAXFRAME * 2;
2374 int ymin = MAXSEQ + 1;
2382 return OPERATOR_CANCELLED;
2384 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
2385 if ((seq->flag & SELECT) || (seq == last_seq)) {
2386 xmin = min_ii(xmin, seq->startdisp);
2387 xmax = max_ii(xmax, seq->enddisp);
2389 ymin = min_ii(ymin, seq->machine);
2390 ymax = max_ii(ymax, seq->machine);
2395 const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
2402 orig_height = BLI_rctf_size_y(&cur_new);
2404 cur_new.xmin = xmin;
2405 cur_new.xmax = xmax;
2407 cur_new.ymin = ymin;
2408 cur_new.ymax = ymax;
2410 /* only zoom out vertically */
2411 if (orig_height > BLI_rctf_size_y(&cur_new)) {
2412 ymid = BLI_rctf_cent_y(&cur_new);
2414 cur_new.ymin = ymid - (orig_height / 2);
2415 cur_new.ymax = ymid + (orig_height / 2);
2418 UI_view2d_smooth_view(C, ar, &cur_new, smooth_viewtx);
2420 return OPERATOR_FINISHED;
2423 return OPERATOR_CANCELLED;
2428 void SEQUENCER_OT_view_selected(wmOperatorType *ot)
2431 ot->name = "View Selected";
2432 ot->idname = "SEQUENCER_OT_view_selected";
2433 ot->description = "Zoom the sequencer on the selected strips";
2436 ot->exec = sequencer_view_selected_exec;
2437 ot->poll = ED_operator_sequencer_active;
2440 ot->flag = OPTYPE_REGISTER;
2444 static int find_next_prev_edit(Scene *scene, int cfra,
2446 const bool do_skip_mute, const bool do_center)
2448 Editing *ed = BKE_sequencer_editing_get(scene, false);
2449 Sequence *seq, *best_seq = NULL, *frame_seq = NULL;
2451 int dist, best_dist;
2452 best_dist = MAXFRAME * 2;
2454 if (ed == NULL) return cfra;
2456 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
2459 if (do_skip_mute && (seq->flag & SEQ_MUTE)) {
2464 seq_frame = (seq->startdisp + seq->enddisp) / 2;
2467 seq_frame = seq->startdisp;
2470 dist = MAXFRAME * 2;
2474 if (seq_frame < cfra) {
2475 dist = cfra - seq_frame;
2478 case SEQ_SIDE_RIGHT:
2479 if (seq_frame > cfra) {
2480 dist = seq_frame - cfra;
2482 else if (seq_frame == cfra) {
2488 if (dist < best_dist) {
2494 /* if no sequence to the right is found and the
2495 * frame is on the start of the last sequence,
2496 * move to the end of the last sequence */
2499 cfra = (frame_seq->startdisp + frame_seq->enddisp) / 2;
2502 cfra = frame_seq->enddisp;
2508 cfra = (best_seq->startdisp + best_seq->enddisp) / 2;
2511 cfra = best_seq->startdisp;
2518 static bool strip_jump_internal(Scene *scene,
2520 const bool do_skip_mute, const bool do_center)
2522 bool changed = false;
2524 int nfra = find_next_prev_edit(scene, cfra, side, do_skip_mute, do_center);
2534 static int sequencer_strip_jump_poll(bContext *C)
2536 /* prevent changes during render */
2540 return sequencer_edit_poll(C);
2543 /* jump frame to edit point operator */
2544 static int sequencer_strip_jump_exec(bContext *C, wmOperator *op)
2546 Scene *scene = CTX_data_scene(C);
2547 const bool next = RNA_boolean_get(op->ptr, "next");
2548 const bool center = RNA_boolean_get(op->ptr, "center");
2550 /* currently do_skip_mute is always true */
2551 if (!strip_jump_internal(scene, next ? SEQ_SIDE_RIGHT : SEQ_SIDE_LEFT, true, center)) {
2552 return OPERATOR_CANCELLED;
2555 WM_event_add_notifier(C, NC_SCENE | ND_FRAME, scene);
2557 return OPERATOR_FINISHED;
2560 void SEQUENCER_OT_strip_jump(wmOperatorType *ot)
2563 ot->name = "Jump to Strip";
2564 ot->idname = "SEQUENCER_OT_strip_jump";
2565 ot->description = "Move frame to previous edit point";
2568 ot->exec = sequencer_strip_jump_exec;
2569 ot->poll = sequencer_strip_jump_poll;
2572 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2575 RNA_def_boolean(ot->srna, "next", true, "Next Strip", "");
2576 RNA_def_boolean(ot->srna, "center", true, "Use strip center", "");
2579 static void swap_sequence(Scene *scene, Sequence *seqa, Sequence *seqb)
2581 int gap = seqb->startdisp - seqa->enddisp;
2585 seq_b_start = (seqb->start - seqb->startdisp) + seqa->startdisp;
2586 BKE_sequence_translate(scene, seqb, seq_b_start - seqb->start);
2587 BKE_sequence_calc(scene, seqb);
2589 seq_a_start = (seqa->start - seqa->startdisp) + seqb->enddisp + gap;
2590 BKE_sequence_translate(scene, seqa, seq_a_start - seqa->start);
2591 BKE_sequence_calc(scene, seqa);
2595 static Sequence *sequence_find_parent(Scene *scene, Sequence *child)
2597 Editing *ed = BKE_sequencer_editing_get(scene, false);
2598 Sequence *parent = NULL;
2601 if (ed == NULL) return NULL;
2603 for (seq = ed->seqbasep->first; seq; seq = seq->next) {
2604 if ((seq != child) && seq_is_parent(seq, child)) {
2614 static int sequencer_swap_exec(bContext *C, wmOperator *op)
2616 Scene *scene = CTX_data_scene(C);
2617 Editing *ed = BKE_sequencer_editing_get(scene, false);
2618 Sequence *active_seq = BKE_sequencer_active_get(scene);
2619 Sequence *seq, *iseq;
2620 int side = RNA_enum_get(op->ptr, "side");
2622 if (active_seq == NULL) return OPERATOR_CANCELLED;
2624 seq = find_next_prev_sequence(scene, active_seq, side, -1);
2628 /* disallow effect strips */
2629 if (BKE_sequence_effect_get_num_inputs(seq->type) >= 1 && (seq->effectdata || seq->seq1 || seq->seq2 || seq->seq3))
2630 return OPERATOR_CANCELLED;
2631 if ((BKE_sequence_effect_get_num_inputs(active_seq->type) >= 1) && (active_seq->effectdata || active_seq->seq1 || active_seq->seq2 || active_seq->seq3))
2632 return OPERATOR_CANCELLED;
2636 swap_sequence(scene, seq, active_seq);
2638 case SEQ_SIDE_RIGHT:
2639 swap_sequence(scene, active_seq, seq);
2643 // XXX - should be a generic function
2644 for (iseq = scene->ed->seqbasep->first; iseq; iseq = iseq->next) {
2645 if ((iseq->type & SEQ_TYPE_EFFECT) && (seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) {
2646 BKE_sequence_calc(scene, iseq);
2650 /* do this in a new loop since both effects need to be calculated first */
2651 for (iseq = scene->ed->seqbasep->first; iseq; iseq = iseq->next) {
2652 if ((iseq->type & SEQ_TYPE_EFFECT) && (seq_is_parent(iseq, active_seq) || seq_is_parent(iseq, seq))) {
2653 /* this may now overlap */
2654 if (BKE_sequence_test_overlap(ed->seqbasep, iseq) ) {
2655 BKE_sequence_base_shuffle(ed->seqbasep, iseq, scene);
2662 BKE_sequencer_sort(scene);
2664 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
2666 return OPERATOR_FINISHED;
2669 return OPERATOR_CANCELLED;
2672 void SEQUENCER_OT_swap(wmOperatorType *ot)
2675 ot->name = "Swap Strip";
2676 ot->idname = "SEQUENCER_OT_swap";
2677 ot->description = "Swap active strip with strip to the right or left";
2680 ot->exec = sequencer_swap_exec;
2681 ot->poll = sequencer_edit_poll;
2684 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2687 RNA_def_enum(ot->srna, "side", prop_side_lr_types, SEQ_SIDE_RIGHT, "Side", "Side of the strip to swap");
2690 static int sequencer_rendersize_exec(bContext *C, wmOperator *UNUSED(op))
2692 int retval = OPERATOR_CANCELLED;
2693 Scene *scene = CTX_data_scene(C);
2694 Sequence *active_seq = BKE_sequencer_active_get(scene);
2695 StripElem *se = NULL;
2697 if (active_seq == NULL)
2698 return OPERATOR_CANCELLED;
2701 if (active_seq->strip) {
2702 switch (active_seq->type) {
2703 case SEQ_TYPE_IMAGE:
2704 se = BKE_sequencer_give_stripelem(active_seq, scene->r.cfra);
2706 case SEQ_TYPE_MOVIE:
2707 se = active_seq->strip->stripdata;
2709 case SEQ_TYPE_SCENE:
2711 case SEQ_TYPE_SOUND_RAM:
2712 case SEQ_TYPE_SOUND_HD:
2719 // prevent setting the render size if sequence values aren't initialized
2720 if ((se->orig_width > 0) && (se->orig_height > 0)) {
2721 scene->r.xsch = se->orig_width;
2722 scene->r.ysch = se->orig_height;
2723 WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene);
2724 retval = OPERATOR_FINISHED;
2731 void SEQUENCER_OT_rendersize(wmOperatorType *ot)
2734 ot->name = "Set Render Size";
2735 ot->idname = "SEQUENCER_OT_rendersize";
2736 ot->description = "Set render size and aspect from active sequence";
2739 ot->exec = sequencer_rendersize_exec;
2740 ot->poll = sequencer_edit_poll;
2743 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2748 static void seq_copy_del_sound(Scene *scene, Sequence *seq)
2750 if (seq->type == SEQ_TYPE_META) {
2752 for (iseq = seq->seqbase.first; iseq; iseq = iseq->next) {
2753 seq_copy_del_sound(scene, iseq);
2756 else if (seq->scene_sound) {
2757 sound_remove_scene_sound(scene, seq->scene_sound);
2758 seq->scene_sound = NULL;
2762 static int sequencer_copy_exec(bContext *C, wmOperator *op)
2764 Scene *scene = CTX_data_scene(C);
2765 Editing *ed = BKE_sequencer_editing_get(scene, false);
2767 ListBase nseqbase = {NULL, NULL};
2769 BKE_sequencer_free_clipboard();
2771 if (BKE_sequence_base_isolated_sel_check(ed->seqbasep) == false) {
2772 BKE_report(op->reports, RPT_ERROR, "Please select all related strips");
2773 return OPERATOR_CANCELLED;
2776 BKE_sequence_base_dupli_recursive(scene, NULL, &nseqbase, ed->seqbasep, SEQ_DUPE_UNIQUE_NAME);
2778 /* To make sure the copied strips have unique names between each other add
2779 * them temporarily to the end of the original seqbase. (bug 25932)
2781 if (nseqbase.first) {
2782 Sequence *seq, *first_seq = nseqbase.first;
2783 BLI_movelisttolist(ed->seqbasep, &nseqbase);
2785 for (seq = first_seq; seq; seq = seq->next)
2786 BKE_sequencer_recursive_apply(seq, apply_unique_name_cb, scene);
2788 seqbase_clipboard.first = first_seq;
2789 seqbase_clipboard.last = ed->seqbasep->last;
2791 if (first_seq->prev) {
2792 first_seq->prev->next = NULL;
2793 ed->seqbasep->last = first_seq->prev;
2794 first_seq->prev = NULL;
2798 seqbase_clipboard_frame = scene->r.cfra;
2800 /* Need to remove anything that references the current scene */
2803 for (seq = seqbase_clipboard.first; seq; seq = seq->next) {
2804 seq_copy_del_sound(scene, seq);
2807 /* duplicate pointers */
2808 for (seq = seqbase_clipboard.first; seq; seq = seq->next) {
2809 BKE_sequence_clipboard_pointers_store(seq);
2813 return OPERATOR_FINISHED;
2816 void SEQUENCER_OT_copy(wmOperatorType *ot)
2820 ot->idname = "SEQUENCER_OT_copy";
2821 ot->description = "";
2824 ot->exec = sequencer_copy_exec;
2825 ot->poll = sequencer_edit_poll;
2828 ot->flag = OPTYPE_REGISTER;
2833 static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op))
2835 Main *bmain = CTX_data_main(C);
2836 Scene *scene = CTX_data_scene(C);
2837 Editing *ed = BKE_sequencer_editing_get(scene, true); /* create if needed */
2838 ListBase nseqbase = {NULL, NULL};
2840 Sequence *iseq, *iseq_first;
2842 ED_sequencer_deselect_all(scene);
2843 ofs = scene->r.cfra - seqbase_clipboard_frame;
2845 BKE_sequence_base_dupli_recursive(scene, NULL, &nseqbase, &seqbase_clipboard, SEQ_DUPE_UNIQUE_NAME);
2847 /* transform pasted strips before adding */
2849 for (iseq = nseqbase.first; iseq; iseq = iseq->next) {
2850 BKE_sequence_translate(scene, iseq, ofs);
2854 for (iseq = nseqbase.first; iseq; iseq = iseq->next) {
2855 BKE_sequence_clipboard_pointers_restore(iseq, bmain);
2858 for (iseq = nseqbase.first; iseq; iseq = iseq->next) {
2859 BKE_sequence_sound_init(scene, iseq);
2862 iseq_first = nseqbase.first;
2864 BLI_movelisttolist(ed->seqbasep, &nseqbase);
2866 /* make sure the pasted strips have unique names between them */
2867 for (iseq = iseq_first; iseq; iseq = iseq->next) {
2868 BKE_sequencer_recursive_apply(iseq, apply_unique_name_cb, scene);
2871 /* ensure pasted strips don't overlap */
2872 for (iseq = iseq_first; iseq; iseq = iseq->next) {
2873 if (BKE_sequence_test_overlap(ed->seqbasep, iseq)) {
2874 BKE_sequence_base_shuffle(ed->seqbasep, iseq, scene);
2878 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
2880 return OPERATOR_FINISHED;
2883 void SEQUENCER_OT_paste(wmOperatorType *ot)
2887 ot->idname = "SEQUENCER_OT_paste";
2888 ot->description = "";
2891 ot->exec = sequencer_paste_exec;
2892 ot->poll = ED_operator_sequencer_active;
2895 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2900 static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
2902 Scene *scene = CTX_data_scene(C);
2904 Sequence *seq_other;
2905 const char *error_msg;
2907 if (BKE_sequencer_active_get_pair(scene, &seq_act, &seq_other) == 0) {
2908 BKE_report(op->reports, RPT_ERROR, "Please select two strips");
2909 return OPERATOR_CANCELLED;
2912 if (BKE_sequence_swap(seq_act, seq_other, &error_msg) == 0) {
2913 BKE_report(op->reports, RPT_ERROR, error_msg);
2914 return OPERATOR_CANCELLED;
2917 if (seq_act->scene_sound)
2918 sound_remove_scene_sound(scene, seq_act->scene_sound);
2920 if (seq_other->scene_sound)
2921 sound_remove_scene_sound(scene, seq_other->scene_sound);
2923 seq_act->scene_sound = NULL;
2924 seq_other->scene_sound = NULL;
2926 BKE_sequence_calc(scene, seq_act);
2927 BKE_sequence_calc(scene, seq_other);
2929 if (seq_act->sound) sound_add_scene_sound_defaults(scene, seq_act);
2930 if (seq_other->sound) sound_add_scene_sound_defaults(scene, seq_other);
2932 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
2934 return OPERATOR_FINISHED;
2937 void SEQUENCER_OT_swap_data(wmOperatorType *ot)
2940 ot->name = "Sequencer Swap Data";
2941 ot->idname = "SEQUENCER_OT_swap_data";
2942 ot->description = "Swap 2 sequencer strips";
2945 ot->exec = sequencer_swap_data_exec;
2946 ot->poll = ED_operator_sequencer_active;
2949 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
2954 /* borderselect operator */
2955 static int view_ghost_border_exec(bContext *C, wmOperator *op)
2957 Scene *scene = CTX_data_scene(C);
2958 View2D *v2d = UI_view2d_fromcontext(C);
2962 /* convert coordinates of rect to 'tot' rect coordinates */
2963 WM_operator_properties_border_to_rctf(op, &rect);
2964 UI_view2d_region_to_view_rctf(v2d, &rect, &rect);
2966 rect.xmin /= fabsf(BLI_rctf_size_x(&v2d->tot));
2967 rect.ymin /= fabsf(BLI_rctf_size_y(&v2d->tot));
2969 rect.xmax /= fabsf(BLI_rctf_size_x(&v2d->tot));
2970 rect.ymax /= fabsf(BLI_rctf_size_y(&v2d->tot));
2977 CLAMP(rect.xmin, 0.0f, 1.0f);
2978 CLAMP(rect.ymin, 0.0f, 1.0f);
2979 CLAMP(rect.xmax, 0.0f, 1.0f);
2980 CLAMP(rect.ymax, 0.0f, 1.0f);
2982 scene->ed->over_border = rect;
2984 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
2986 return OPERATOR_FINISHED;
2989 /* ****** Border Select ****** */
2990 void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot)
2993 ot->name = "Border Offset View";
2994 ot->idname = "SEQUENCER_OT_view_ghost_border";
2995 ot->description = "Set the boundaries of the border used for offset-view";
2998 ot->invoke = WM_border_select_invoke;
2999 ot->exec = view_ghost_border_exec;
3000 ot->modal = WM_border_select_modal;
3001 ot->poll = sequencer_view_poll;
3002 ot->cancel = WM_border_select_cancel;
3008 WM_operator_properties_gesture_border(ot, false);
3011 /* rebuild_proxy operator */
3012 static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
3014 seq_proxy_build_job(C);
3016 return OPERATOR_FINISHED;
3019 void SEQUENCER_OT_rebuild_proxy(wmOperatorType *ot)
3022 ot->name = "Rebuild Proxy and Timecode Indices";
3023 ot->idname = "SEQUENCER_OT_rebuild_proxy";
3024 ot->description = "Rebuild all selected proxies and timecode indices using the job system";
3027 ot->exec = sequencer_rebuild_proxy_exec;
3028 ot->poll = ED_operator_sequencer_active;
3031 ot->flag = OPTYPE_REGISTER;
3036 static EnumPropertyItem prop_change_effect_input_types[] = {
3037 {0, "A_B", 0, "A -> B", ""},
3038 {1, "B_C", 0, "B -> C", ""},
3039 {2, "A_C", 0, "A -> C", ""},
3040 {0, NULL, 0, NULL, NULL}
3043 static int sequencer_change_effect_input_exec(bContext *C, wmOperator *op)
3045 Scene *scene = CTX_data_scene(C);
3046 Editing *ed = BKE_sequencer_editing_get(scene, false);
3047 Sequence *seq = BKE_sequencer_active_get(scene);
3049 Sequence **seq_1, **seq_2;
3051 switch (RNA_enum_get(op->ptr, "swap")) {
3066 if (*seq_1 == NULL || *seq_2 == NULL) {
3067 BKE_report(op->reports, RPT_ERROR, "One of the effect inputs is unset, cannot swap");
3068 return OPERATOR_CANCELLED;
3071 SWAP(Sequence *, *seq_1, *seq_2);
3074 BKE_sequencer_update_changed_seq_and_deps(scene, seq, 0, 1);
3076 /* important else we don't get the imbuf cache flushed */
3077 BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
3079 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
3081 return OPERATOR_FINISHED;
3084 void SEQUENCER_OT_change_effect_input(struct wmOperatorType *ot)
3087 ot->name = "Change Effect Input";
3088 ot->idname = "SEQUENCER_OT_change_effect_input";
3089 ot->description = "";
3092 ot->exec = sequencer_change_effect_input_exec;
3093 ot->poll = sequencer_effect_poll;
3096 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3098 ot->prop = RNA_def_enum(ot->srna, "swap", prop_change_effect_input_types, 0, "Swap", "The effect inputs to swap");
3101 static int sequencer_change_effect_type_exec(bContext *C, wmOperator *op)
3103 Scene *scene = CTX_data_scene(C);
3104 Editing *ed = BKE_sequencer_editing_get(scene, false);
3105 Sequence *seq = BKE_sequencer_active_get(scene);
3106 const int new_type = RNA_enum_get(op->ptr, "type");
3108 /* free previous effect and init new effect */
3109 struct SeqEffectHandle sh;
3111 if ((seq->type & SEQ_TYPE_EFFECT) == 0) {
3112 return OPERATOR_CANCELLED;
3115 /* can someone explain the logic behind only allowing to increase this,
3116 * copied from 2.4x - campbell */
3117 if (BKE_sequence_effect_get_num_inputs(seq->type) <
3118 BKE_sequence_effect_get_num_inputs(new_type))
3120 BKE_report(op->reports, RPT_ERROR, "New effect needs more input strips");
3121 return OPERATOR_CANCELLED;
3124 sh = BKE_sequence_get_effect(seq);
3127 seq->type = new_type;
3129 sh = BKE_sequence_get_effect(seq);
3134 BKE_sequencer_update_changed_seq_and_deps(scene, seq, 0, 1);
3136 /* important else we don't get the imbuf cache flushed */
3137 BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
3139 WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
3141 return OPERATOR_FINISHED;
3144 void SEQUENCER_OT_change_effect_type(struct wmOperatorType *ot)
3147 ot->name = "Change Effect Type";
3148 ot->idname = "SEQUENCER_OT_change_effect_type";
3149 ot->description = "";
3152 ot->exec = sequencer_change_effect_type_exec;
3153 ot->poll = sequencer_effect_poll;
3156 ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
3158 ot->prop = RNA_def_enum(ot->srna, "type", sequencer_prop_effect_types, SEQ_TYPE_CROSS, "Type", "Sequencer effect type");
3161 static int sequencer_change_path_exec(bContext *C, wmOperator *op)
3163 Main *bmain = CTX_data_main(C);
3164 Scene *scene = CTX_data_scene(C);
3165 Editing *ed = BKE_sequencer_editing_get(scene, false);
3166 Sequence *seq = BKE_sequencer_active_get(scene);
3167 const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
3169 if (seq->type == SEQ_TYPE_IMAGE) {
3170 char directory[FILE_MAX];
3171 const int len = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
3175 return OPERATOR_CANCELLED;
3177 RNA_string_get(op->ptr, "directory", directory);
3178 if (is_relative_path) {
3179 /* TODO, shouldn't this already be relative from the filesel?
3180 * (as the 'filepath' is) for now just make relative here,
3181 * but look into changing after 2.60 - campbell */
3182 BLI_path_rel(directory, bmain->name);
3184 BLI_strncpy(seq->strip->dir, directory, sizeof(seq->strip->dir));
3186 if (seq->strip->stripdata) {
3187 MEM_freeN(seq->strip->stripdata);
3189 seq->strip->stripdata = se = MEM_callocN(len * sizeof(StripElem), "stripelem");
3191 RNA_BEGIN (op->ptr, itemptr, "files")
3193 char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
3194 BLI_strncpy(se->name, filename, sizeof(se->name));
3195 MEM_freeN(filename);
3200 /* reset these else we wont see all the images */
3201 seq->anim_startofs = seq->anim_endofs = 0;
3203 /* correct start/end frames so we don't move
3204 * important not to set seq->len = len; allow the function to handle it */