Cleanup: left wrong comment in
[blender-staging.git] / source / blender / editors / space_sequencer / sequencer_edit.c
index aaf398bf3a1ff432b6aa9cae4438acc69d7d68f8..0895d28fba75fe7bd86f0997029e739c9ff4e4a8 100644 (file)
 #include "MEM_guardedalloc.h"
 
 #include "BLI_blenlib.h"
+#include "BLI_ghash.h"
 #include "BLI_math.h"
+#include "BLI_timecode.h"
 #include "BLI_utildefines.h"
-#include "BLI_ghash.h"
 
-#include "BLF_translation.h"
+#include "BLT_translation.h"
 
 #include "DNA_scene_types.h"
+#include "DNA_sound_types.h"
 
 #include "BKE_context.h"
 #include "BKE_global.h"
@@ -59,6 +61,7 @@
 
 /* for menu/popup icons etc etc*/
 
+#include "ED_anim_api.h"
 #include "ED_numinput.h"
 #include "ED_screen.h"
 #include "ED_transform.h"
@@ -91,6 +94,8 @@ EnumPropertyItem sequencer_prop_effect_types[] = {
        {SEQ_TYPE_MULTICAM, "MULTICAM", 0, "Multicam Selector", ""},
        {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""},
        {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""},
+       {SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""},
+       {SEQ_TYPE_COLORMIX, "COLORMIX", 0, "Color Mix", ""},
        {0, NULL, 0, NULL, NULL}
 };
 
@@ -103,7 +108,7 @@ EnumPropertyItem prop_side_types[] = {
        {0, NULL, 0, NULL, NULL}
 };
 
-static EnumPropertyItem prop_side_lr_types[] = {
+static const EnumPropertyItem prop_side_lr_types[] = {
        {SEQ_SIDE_LEFT, "LEFT", 0, "Left", ""},
        {SEQ_SIDE_RIGHT, "RIGHT", 0, "Right", ""},
        {0, NULL, 0, NULL, NULL}
@@ -180,8 +185,6 @@ static void seq_proxy_build_job(const bContext *C)
        Scene *scene = CTX_data_scene(C);
        Editing *ed = BKE_sequencer_editing_get(scene, false);
        ScrArea *sa = CTX_wm_area(C);
-       struct SeqIndexBuildContext *context;
-       LinkData *link;
        Sequence *seq;
        GSet *file_list;
        
@@ -209,9 +212,7 @@ static void seq_proxy_build_job(const bContext *C)
        SEQP_BEGIN (ed, seq)
        {
                if ((seq->flag & SELECT)) {
-                       context = BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq, file_list);
-                       link = BLI_genericNodeN(context);
-                       BLI_addtail(&pj->queue, link);
+                       BKE_sequencer_proxy_rebuild_context(pj->main, pj->scene, seq, file_list, &pj->queue);
                }
        }
        SEQ_END
@@ -562,7 +563,7 @@ int seq_effect_find_selected(Scene *scene, Sequence *activeseq, int type, Sequen
                        }
                        if (seq1 == NULL) seq1 = seq2;
                        if (seq3 == NULL) seq3 = seq2;
-                       /* fall-through */
+                       ATTR_FALLTHROUGH;
                case 2:
                        if (seq1 == NULL || seq2 == NULL) {
                                *error_str = N_("2 selected sequence strips are needed");
@@ -670,6 +671,9 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
        Sequence *seqn = NULL;
        bool skip_dup = false;
 
+       /* Unlike soft-cut, it's important to use the same value for both strips. */
+       const bool is_end_exact = ((seq->start + seq->len) == cutframe);
+
        /* backup values */
        ts.start = seq->start;
        ts.machine = seq->machine;
@@ -682,11 +686,21 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
        ts.anim_startofs = seq->anim_startofs;
        ts.anim_endofs = seq->anim_endofs;
        ts.len = seq->len;
-       
+
        /* First Strip! */
        /* strips with extended stillfames before */
        
-       if ((seq->startstill) && (cutframe < seq->start)) {
+       /* Precaution, needed because the length saved on-disk may not match the length saved in the blend file,
+        * or our code may have minor differences reading file length between versions.
+        * This causes hard-cut to fail, see: T47862 */
+       if (seq->type != SEQ_TYPE_META) {
+               BKE_sequence_reload_new_file(scene, seq, true);
+               BKE_sequence_calc(scene, seq);
+       }
+
+       /* Important to offset the start when 'cutframe == seq->start'
+        * because we need at least one frame of content after start/end still have clipped it. */
+       if ((seq->startstill) && (cutframe <= seq->start)) {
                /* don't do funny things with METAs ... */
                if (seq->type == SEQ_TYPE_META) {
                        skip_dup = true;
@@ -700,13 +714,17 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
                }
        }
        /* normal strip */
-       else if ((cutframe >= seq->start) && (cutframe <= (seq->start + seq->len))) {
+       else if ((is_end_exact == false) &&
+                ((cutframe >= seq->start) && (cutframe <= (seq->start + seq->len))))
+       {
                seq->endofs = 0;
                seq->endstill = 0;
                seq->anim_endofs += (seq->start + seq->len) - cutframe;
        }
        /* strips with extended stillframes after */
-       else if (((seq->start + seq->len) < cutframe) && (seq->endstill)) {
+       else if ((is_end_exact == true) ||
+                (((seq->start + seq->len) < cutframe) && (seq->endstill)))
+       {
                seq->endstill -= seq->enddisp - cutframe;
                /* don't do funny things with METAs ... */
                if (seq->type == SEQ_TYPE_META) {
@@ -719,12 +737,16 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
 
        if (!skip_dup) {
                /* Duplicate AFTER the first change */
-               seqn = BKE_sequence_dupli_recursive(scene, NULL, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
+               seqn = BKE_sequence_dupli_recursive(scene, scene, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
        }
        
        if (seqn) {
                seqn->flag |= SELECT;
-                       
+
+               /* Important not to re-assign this (unlike soft-cut) */
+#if 0
+               is_end_exact = ((seqn->start + seqn->len) == cutframe);
+#endif
                /* Second Strip! */
                /* strips with extended stillframes before */
                if ((seqn->startstill) && (cutframe == seqn->start + 1)) {
@@ -733,9 +755,11 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
                        seqn->anim_endofs = ts.anim_endofs;
                        seqn->endstill = ts.endstill;
                }
-               
+
                /* normal strip */
-               else if ((cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len))) {
+               else if ((is_end_exact == false) &&
+                        ((cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len))))
+               {
                        seqn->start = cutframe;
                        seqn->startstill = 0;
                        seqn->startofs = 0;
@@ -744,16 +768,18 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe)
                        seqn->anim_endofs = ts.anim_endofs;
                        seqn->endstill = ts.endstill;
                }
-               
+
                /* strips with extended stillframes after */
-               else if (((seqn->start + seqn->len) < cutframe) && (seqn->endstill)) {
+               else if ((is_end_exact == true) ||
+                        (((seqn->start + seqn->len) < cutframe) && (seqn->endstill)))
+               {
                        seqn->start = cutframe;
                        seqn->startofs = 0;
                        seqn->anim_startofs += ts.len - 1;
                        seqn->endstill = ts.enddisp - cutframe - 1;
                        seqn->startstill = 0;
                }
-               
+
                BKE_sequence_reload_new_file(scene, seqn, false);
                BKE_sequence_calc(scene, seqn);
        }
@@ -766,6 +792,8 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
        Sequence *seqn = NULL;
        bool skip_dup = false;
 
+       bool is_end_exact = ((seq->start + seq->len) == cutframe);
+
        /* backup values */
        ts.start = seq->start;
        ts.machine = seq->machine;
@@ -778,11 +806,13 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
        ts.anim_startofs = seq->anim_startofs;
        ts.anim_endofs = seq->anim_endofs;
        ts.len = seq->len;
-       
+
        /* First Strip! */
        /* strips with extended stillfames before */
-       
-       if ((seq->startstill) && (cutframe < seq->start)) {
+
+       /* Important to offset the start when 'cutframe == seq->start'
+        * because we need at least one frame of content after start/end still have clipped it. */
+       if ((seq->startstill) && (cutframe <= seq->start)) {
                /* don't do funny things with METAs ... */
                if (seq->type == SEQ_TYPE_META) {
                        skip_dup = true;
@@ -796,11 +826,15 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
                }
        }
        /* normal strip */
-       else if ((cutframe >= seq->start) && (cutframe <= (seq->start + seq->len))) {
+       else if ((is_end_exact == false) &&
+                (cutframe >= seq->start) && (cutframe <= (seq->start + seq->len)))
+       {
                seq->endofs = (seq->start + seq->len) - cutframe;
        }
        /* strips with extended stillframes after */
-       else if (((seq->start + seq->len) < cutframe) && (seq->endstill)) {
+       else if ((is_end_exact == true) ||
+                (((seq->start + seq->len) < cutframe) && (seq->endstill)))
+       {
                seq->endstill -= seq->enddisp - cutframe;
                /* don't do funny things with METAs ... */
                if (seq->type == SEQ_TYPE_META) {
@@ -812,12 +846,14 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
 
        if (!skip_dup) {
                /* Duplicate AFTER the first change */
-               seqn = BKE_sequence_dupli_recursive(scene, NULL, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
+               seqn = BKE_sequence_dupli_recursive(scene, scene, seq, SEQ_DUPE_UNIQUE_NAME | SEQ_DUPE_ANIM);
        }
        
        if (seqn) {
                seqn->flag |= SELECT;
-                       
+
+               is_end_exact = ((seqn->start + seqn->len) == cutframe);
+
                /* Second Strip! */
                /* strips with extended stillframes before */
                if ((seqn->startstill) && (cutframe == seqn->start + 1)) {
@@ -826,23 +862,27 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe)
                        seqn->endofs = ts.endofs;
                        seqn->endstill = ts.endstill;
                }
-               
+
                /* normal strip */
-               else if ((cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len))) {
+               else if ((is_end_exact == false) &&
+                        (cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len)))
+               {
                        seqn->startstill = 0;
                        seqn->startofs = cutframe - ts.start;
                        seqn->endofs = ts.endofs;
                        seqn->endstill = ts.endstill;
                }
-               
+
                /* strips with extended stillframes after */
-               else if (((seqn->start + seqn->len) < cutframe) && (seqn->endstill)) {
+               else if ((is_end_exact == true) ||
+                        (((seqn->start + seqn->len) < cutframe) && (seqn->endstill)))
+               {
                        seqn->start = cutframe - ts.len + 1;
                        seqn->startofs = ts.len - 1;
                        seqn->endstill = ts.enddisp - cutframe - 1;
                        seqn->startstill = 0;
                }
-               
+
                BKE_sequence_calc(scene, seqn);
        }
        return seqn;
@@ -904,6 +944,7 @@ static bool sequence_offset_after_frame(Scene *scene, const int delta, const int
        Sequence *seq;
        Editing *ed = BKE_sequencer_editing_get(scene, false);
        bool done = false;
+       TimeMarker *marker;
 
        /* all strips >= cfra are shifted */
        
@@ -917,38 +958,15 @@ static bool sequence_offset_after_frame(Scene *scene, const int delta, const int
                }
        }
 
-       return done;
-}
-
-static void UNUSED_FUNCTION(touch_seq_files) (Scene *scene)
-{
-       Sequence *seq;
-       Editing *ed = BKE_sequencer_editing_get(scene, false);
-       char str[256];
-
-       /* touch all strips with movies */
-       
-       if (ed == NULL) return;
-
-       // XXX25 if (okee("Touch and print selected movies")==0) return;
-
-       WM_cursor_wait(1);
-
-       SEQP_BEGIN (ed, seq)
-       {
-               if (seq->flag & SELECT) {
-                       if (seq->type == SEQ_TYPE_MOVIE) {
-                               if (seq->strip && seq->strip->stripdata) {
-                                       BLI_make_file_string(G.main->name, str, seq->strip->dir, seq->strip->stripdata->name);
-                                       BLI_file_touch(seq->name);
-                               }
+       if (!scene->toolsettings->lock_markers) {
+               for (marker = scene->markers.first; marker; marker = marker->next) {
+                       if (marker->frame >= cfra) {
+                               marker->frame += delta;
                        }
-
                }
        }
-       SEQ_END
 
-       WM_cursor_wait(0);
+       return done;
 }
 
 #if 0
@@ -988,11 +1006,11 @@ static void UNUSED_FUNCTION(seq_remap_paths) (Scene *scene)
                return;
        
        BLI_strncpy(from, last_seq->strip->dir, sizeof(from));
-// XXX if (0 == sbutton(from, 0, sizeof(from)-1, "From: "))
+// XXX if (0 == sbutton(from, 0, sizeof(from) - 1, "From: "))
 //             return;
        
        BLI_strncpy(to, from, sizeof(to));
-// XXX if (0 == sbutton(to, 0, sizeof(to)-1, "To: "))
+// XXX if (0 == sbutton(to, 0, sizeof(to) - 1, "To: "))
 //             return;
        
        if (STREQ(to, from))
@@ -1039,7 +1057,7 @@ static int sequencer_gap_remove_exec(bContext *C, wmOperator *op)
                        break;
                }
        }
-       
+
        for ( ; cfra < efra; cfra++) {
                /* first == 0 means there's still no strip to remove a gap for */
                if (first == false) {
@@ -1198,6 +1216,7 @@ static int sequencer_snap_exec(bContext *C, wmOperator *op)
                                        BKE_sequence_tx_set_final_right(seq, snap_frame);
                                }
                                BKE_sequence_tx_handle_xlimits(seq, seq->flag & SEQ_LEFTSEL, seq->flag & SEQ_RIGHTSEL);
+                               BKE_sequence_single_fix(seq);
                        }
                        BKE_sequence_calc(scene, seq);
                }
@@ -1245,7 +1264,7 @@ static int sequencer_snap_invoke(bContext *C, wmOperator *op, const wmEvent *UNU
 void SEQUENCER_OT_snap(struct wmOperatorType *ot)
 {
        /* identifiers */
-       ot->name = "Snap Strips";
+       ot->name = "Snap Strips to Frame";
        ot->idname = "SEQUENCER_OT_snap";
        ot->description = "Frame where selected strips will be snapped";
        
@@ -1519,23 +1538,20 @@ static int sequencer_slip_exec(bContext *C, wmOperator *op)
 
 static void sequencer_slip_update_header(Scene *scene, ScrArea *sa, SlipData *data, int offset)
 {
-#define HEADER_LENGTH 40
-       char msg[HEADER_LENGTH];
+       char msg[UI_MAX_DRAW_STR];
 
        if (sa) {
                if (hasNumInput(&data->num_input)) {
                        char num_str[NUM_STR_REP_LEN];
                        outputNumInput(&data->num_input, num_str, &scene->unit);
-                       BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %s", num_str);
+                       BLI_snprintf(msg, sizeof(msg), IFACE_("Trim offset: %s"), num_str);
                }
                else {
-                       BLI_snprintf(msg, HEADER_LENGTH, "Trim offset: %d", offset);
+                       BLI_snprintf(msg, sizeof(msg), IFACE_("Trim offset: %d"), offset);
                }
        }
 
        ED_area_headerprint(sa, msg);
-
-#undef HEADER_LENGTH
 }
 
 static int sequencer_slip_modal(bContext *C, wmOperator *op, const wmEvent *event)
@@ -1742,7 +1758,7 @@ void SEQUENCER_OT_mute(struct wmOperatorType *ot)
        /* identifiers */
        ot->name = "Mute Strips";
        ot->idname = "SEQUENCER_OT_mute";
-       ot->description = "Mute selected strips";
+       ot->description = "Mute (un)selected strips";
        
        /* api callbacks */
        ot->exec = sequencer_mute_exec;
@@ -1793,7 +1809,7 @@ void SEQUENCER_OT_unmute(struct wmOperatorType *ot)
        /* identifiers */
        ot->name = "Un-Mute Strips";
        ot->idname = "SEQUENCER_OT_unmute";
-       ot->description = "Un-Mute unselected rather than selected strips";
+       ot->description = "Unmute (un)selected strips";
        
        /* api callbacks */
        ot->exec = sequencer_unmute_exec;
@@ -1802,7 +1818,7 @@ void SEQUENCER_OT_unmute(struct wmOperatorType *ot)
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
        
-       RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "UnMute unselected rather than selected strips");
+       RNA_def_boolean(ot->srna, "unselected", 0, "Unselected", "Unmute unselected rather than selected strips");
 }
 
 
@@ -1919,6 +1935,14 @@ void SEQUENCER_OT_reload(struct wmOperatorType *ot)
 }
 
 /* reload operator */
+static int sequencer_refresh_all_poll(bContext *C)
+{
+       if (G.is_rendering) {
+               return 0;
+       }
+       return sequencer_edit_poll(C);
+}
+
 static int sequencer_refresh_all_exec(bContext *C, wmOperator *UNUSED(op))
 {
        Scene *scene = CTX_data_scene(C);
@@ -1940,7 +1964,7 @@ void SEQUENCER_OT_refresh_all(struct wmOperatorType *ot)
        
        /* api callbacks */
        ot->exec = sequencer_refresh_all_exec;
-       ot->poll = sequencer_edit_poll;
+       ot->poll = sequencer_refresh_all_poll;
 }
 
 static int sequencer_reassign_inputs_exec(bContext *C, wmOperator *op)
@@ -2041,7 +2065,7 @@ void SEQUENCER_OT_swap_inputs(struct wmOperatorType *ot)
 
 
 /* cut operator */
-static EnumPropertyItem prop_cut_types[] = {
+static const EnumPropertyItem prop_cut_types[] = {
        {SEQ_CUT_SOFT, "SOFT", 0, "Soft", ""},
        {SEQ_CUT_HARD, "HARD", 0, "Hard", ""},
        {0, NULL, 0, NULL, NULL}
@@ -2170,7 +2194,7 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op))
        if (ed == NULL)
                return OPERATOR_CANCELLED;
 
-       BKE_sequence_base_dupli_recursive(scene, NULL, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT);
+       BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, ed->seqbasep, SEQ_DUPE_CONTEXT, 0);
 
        if (nseqbase.first) {
                Sequence *seq = nseqbase.first;
@@ -2202,7 +2226,7 @@ void SEQUENCER_OT_duplicate(wmOperatorType *ot)
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
        
        /* to give to transform */
-       RNA_def_enum(ot->srna, "mode", transform_mode_types, TFM_TRANSLATION, "Mode", "");
+       RNA_def_enum(ot->srna, "mode", rna_enum_transform_mode_types, TFM_TRANSLATION, "Mode", "");
 }
 
 /* delete operator */
@@ -2212,23 +2236,24 @@ static int sequencer_delete_exec(bContext *C, wmOperator *UNUSED(op))
        Editing *ed = BKE_sequencer_editing_get(scene, false);
        Sequence *seq;
        MetaStack *ms;
-       bool nothingSelected = true;
+       bool nothing_selected = true;
 
        seq = BKE_sequencer_active_get(scene);
        if (seq && seq->flag & SELECT) { /* avoid a loop since this is likely to be selected */
-               nothingSelected = false;
+               nothing_selected = false;
        }
        else {
                for (seq = ed->seqbasep->first; seq; seq = seq->next) {
                        if (seq->flag & SELECT) {
-                               nothingSelected = false;
+                               nothing_selected = false;
                                break;
                        }
                }
        }
 
-       if (nothingSelected)
+       if (nothing_selected) {
                return OPERATOR_FINISHED;
+       }
 
        /* for effects and modifiers, try to find a replacement input */
        for (seq = ed->seqbasep->first; seq; seq = seq->next) {
@@ -2370,7 +2395,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op)
                        /* remove seq so overlap tests don't conflict,
                         * see seq_free_sequence below for the real free'ing */
                        BLI_remlink(ed->seqbasep, seq);
-                       /* if (seq->ipo) seq->ipo->id.us--; */
+                       /* if (seq->ipo) id_us_min(&seq->ipo->id); */
                        /* XXX, remove fcurve and assign to split image strips */
 
                        start_ofs = cfra = BKE_sequence_tx_get_final_left(seq, false);
@@ -2440,7 +2465,7 @@ void SEQUENCER_OT_images_separate(wmOperatorType *ot)
        
        /* api callbacks */
        ot->exec = sequencer_separate_images_exec;
-       ot->invoke = WM_operator_props_popup;
+       ot->invoke = WM_operator_props_popup_confirm;
        ot->poll = sequencer_edit_poll;
        
        /* flags */
@@ -2500,6 +2525,7 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op))
 #if 1
                BKE_sequence_tx_set_final_left(ms->parseq, ms->disp_range[0]);
                BKE_sequence_tx_set_final_right(ms->parseq, ms->disp_range[1]);
+               BKE_sequence_single_fix(ms->parseq);
                BKE_sequence_calc(scene, ms->parseq);
 #else
                if (BKE_sequence_test_overlap(ed->seqbasep, ms->parseq))
@@ -2702,6 +2728,29 @@ void SEQUENCER_OT_view_all(wmOperatorType *ot)
        ot->flag = OPTYPE_REGISTER;
 }
 
+static int sequencer_view_frame_exec(bContext *C, wmOperator *op)
+{
+       const int smooth_viewtx = WM_operator_smooth_viewtx_get(op);
+       ANIM_center_frame(C, smooth_viewtx);
+       
+       return OPERATOR_FINISHED;
+}
+
+void SEQUENCER_OT_view_frame(wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "View Frame";
+       ot->idname = "SEQUENCER_OT_view_frame";
+       ot->description = "Reset viewable area to show range around current frame";
+       
+       /* api callbacks */
+       ot->exec = sequencer_view_frame_exec;
+       ot->poll = ED_operator_sequencer_active;
+       
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+}
+
 /* view_all operator */
 static int sequencer_view_all_preview_exec(bContext *C, wmOperator *UNUSED(op))
 {
@@ -2782,7 +2831,7 @@ static int sequencer_view_zoom_ratio_exec(bContext *C, wmOperator *op)
        float facx = BLI_rcti_size_x(&v2d->mask) / winx;
        float facy = BLI_rcti_size_y(&v2d->mask) / winy;
 
-       BLI_rctf_resize(&v2d->cur, floorf(winx * facx / ratio + 0.5f), floorf(winy * facy / ratio + 0.5f));
+       BLI_rctf_resize(&v2d->cur, ceilf(winx * facx / ratio + 0.5f), ceilf(winy * facy / ratio + 0.5f));
 
        ED_region_tag_redraw(CTX_wm_region(C));
 
@@ -2807,7 +2856,7 @@ void SEQUENCER_OT_view_zoom_ratio(wmOperatorType *ot)
 
 
 #if 0
-static EnumPropertyItem view_type_items[] = {
+static const EnumPropertyItem view_type_items[] = {
        {SEQ_VIEW_SEQUENCE, "SEQUENCER", ICON_SEQ_SEQUENCER, "Sequencer", ""},
        {SEQ_VIEW_PREVIEW,  "PREVIEW", ICON_SEQ_PREVIEW, "Image Preview", ""},
        {SEQ_VIEW_SEQUENCE_PREVIEW,  "SEQUENCER_PREVIEW", ICON_SEQ_SEQUENCER, "Sequencer and Image Preview", ""},
@@ -3165,7 +3214,7 @@ static void seq_copy_del_sound(Scene *scene, Sequence *seq)
                }
        }
        else if (seq->scene_sound) {
-               sound_remove_scene_sound(scene, seq->scene_sound);
+               BKE_sound_remove_scene_sound(scene, seq->scene_sound);
                seq->scene_sound = NULL;
        }
 }
@@ -3184,7 +3233,7 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op)
                return OPERATOR_CANCELLED;
        }
 
-       BKE_sequence_base_dupli_recursive(scene, NULL, &nseqbase, ed->seqbasep, SEQ_DUPE_UNIQUE_NAME);
+       BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, ed->seqbasep, SEQ_DUPE_UNIQUE_NAME, 0);
 
        /* To make sure the copied strips have unique names between each other add
         * them temporarily to the end of the original seqbase. (bug 25932)
@@ -3251,7 +3300,7 @@ static int sequencer_paste_exec(bContext *C, wmOperator *UNUSED(op))
        ED_sequencer_deselect_all(scene);
        ofs = scene->r.cfra - seqbase_clipboard_frame;
 
-       BKE_sequence_base_dupli_recursive(scene, NULL, &nseqbase, &seqbase_clipboard, SEQ_DUPE_UNIQUE_NAME);
+       BKE_sequence_base_dupli_recursive(scene, scene, &nseqbase, &seqbase_clipboard, SEQ_DUPE_UNIQUE_NAME, 0);
 
        /* transform pasted strips before adding */
        if (ofs) {
@@ -3322,10 +3371,10 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
        }
 
        if (seq_act->scene_sound)
-               sound_remove_scene_sound(scene, seq_act->scene_sound);
+               BKE_sound_remove_scene_sound(scene, seq_act->scene_sound);
 
        if (seq_other->scene_sound)
-               sound_remove_scene_sound(scene, seq_other->scene_sound);
+               BKE_sound_remove_scene_sound(scene, seq_other->scene_sound);
 
        seq_act->scene_sound = NULL;
        seq_other->scene_sound = NULL;
@@ -3333,8 +3382,11 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
        BKE_sequence_calc(scene, seq_act);
        BKE_sequence_calc(scene, seq_other);
 
-       if (seq_act->sound) sound_add_scene_sound_defaults(scene, seq_act);
-       if (seq_other->sound) sound_add_scene_sound_defaults(scene, seq_other);
+       if (seq_act->sound) BKE_sound_add_scene_sound_defaults(scene, seq_act);
+       if (seq_other->sound) BKE_sound_add_scene_sound_defaults(scene, seq_other);
+
+       BKE_sequence_invalidate_cache(scene, seq_act);
+       BKE_sequence_invalidate_cache(scene, seq_other);
 
        WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene);
 
@@ -3402,17 +3454,17 @@ void SEQUENCER_OT_view_ghost_border(wmOperatorType *ot)
        ot->description = "Set the boundaries of the border used for offset-view";
 
        /* api callbacks */
-       ot->invoke = WM_border_select_invoke;
+       ot->invoke = WM_gesture_border_invoke;
        ot->exec = view_ghost_border_exec;
-       ot->modal = WM_border_select_modal;
+       ot->modal = WM_gesture_border_modal;
        ot->poll = sequencer_view_preview_poll;
-       ot->cancel = WM_border_select_cancel;
+       ot->cancel = WM_gesture_border_cancel;
 
        /* flags */
        ot->flag = 0;
 
        /* rna */
-       WM_operator_properties_gesture_border(ot, false);
+       WM_operator_properties_gesture_border(ot);
 }
 
 /* rebuild_proxy operator */
@@ -3442,12 +3494,18 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op))
        SEQP_BEGIN(ed, seq)
        {
                if ((seq->flag & SELECT)) {
-                       struct SeqIndexBuildContext *context;
+                       ListBase queue = {NULL, NULL};
+                       LinkData *link;
                        short stop = 0, do_update;
                        float progress;
-                       context = BKE_sequencer_proxy_rebuild_context(bmain, scene, seq, file_list);
-                       BKE_sequencer_proxy_rebuild(context, &stop, &do_update, &progress);
-                       BKE_sequencer_proxy_rebuild_finish(context, 0);
+
+                       BKE_sequencer_proxy_rebuild_context(bmain, scene, seq, file_list, &queue);
+
+                       for (link = queue.first; link; link = link->next) {
+                               struct SeqIndexBuildContext *context = link->data;
+                               BKE_sequencer_proxy_rebuild(context, &stop, &do_update, &progress);
+                               BKE_sequencer_proxy_rebuild_finish(context, 0);
+                       }
                        BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
                }
        }
@@ -3487,7 +3545,7 @@ static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
        bool proxy_50 = RNA_boolean_get(op->ptr, "proxy_50");
        bool proxy_75 = RNA_boolean_get(op->ptr, "proxy_75");
        bool proxy_100 = RNA_boolean_get(op->ptr, "proxy_100");
-       bool override = RNA_boolean_get(op->ptr, "override");
+       bool overwrite = RNA_boolean_get(op->ptr, "overwrite");
        bool turnon = true;
 
        if (ed == NULL || !(proxy_25 || proxy_50 || proxy_75 || proxy_100)) {
@@ -3523,7 +3581,7 @@ static int sequencer_enable_proxies_exec(bContext *C, wmOperator *op)
                                else 
                                        seq->strip->proxy->build_size_flags &= ~SEQ_PROXY_IMAGE_SIZE_100;
                                
-                               if (!override)
+                               if (!overwrite)
                                        seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING;
                                else 
                                        seq->strip->proxy->build_flags &= ~SEQ_PROXY_SKIP_EXISTING;
@@ -3555,12 +3613,12 @@ void SEQUENCER_OT_enable_proxies(wmOperatorType *ot)
        RNA_def_boolean(ot->srna, "proxy_50", false, "50%", "");
        RNA_def_boolean(ot->srna, "proxy_75", false, "75%", "");
        RNA_def_boolean(ot->srna, "proxy_100", false, "100%", "");
-       RNA_def_boolean(ot->srna, "override", false, "Override", "");
+       RNA_def_boolean(ot->srna, "overwrite", false, "Overwrite", "");
 }
 
 /* change ops */
 
-static EnumPropertyItem prop_change_effect_input_types[] = {
+static const EnumPropertyItem prop_change_effect_input_types[] = {
        {0, "A_B", 0, "A -> B", ""},
        {1, "B_C", 0, "B -> C", ""},
        {2, "A_C", 0, "A -> C", ""},
@@ -3692,12 +3750,21 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
        Editing *ed = BKE_sequencer_editing_get(scene, false);
        Sequence *seq = BKE_sequencer_active_get(scene);
        const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path");
+       const bool use_placeholders = RNA_boolean_get(op->ptr, "use_placeholders");
+       int minframe, numdigits;
 
        if (seq->type == SEQ_TYPE_IMAGE) {
                char directory[FILE_MAX];
-               const int len = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
+               int len;
                StripElem *se;
 
+               /* need to find min/max frame for placeholders */
+               if (use_placeholders) {
+                       len = sequencer_image_seq_get_minmax_frame(op, seq->sfra, &minframe, &numdigits);
+               }
+               else {
+                       len = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files"));
+               }
                if (len == 0)
                        return OPERATOR_CANCELLED;
 
@@ -3715,14 +3782,19 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
                }
                seq->strip->stripdata = se = MEM_callocN(len * sizeof(StripElem), "stripelem");
 
-               RNA_BEGIN (op->ptr, itemptr, "files")
-               {
-                       char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
-                       BLI_strncpy(se->name, filename, sizeof(se->name));
-                       MEM_freeN(filename);
-                       se++;
+               if (use_placeholders) {
+                       sequencer_image_seq_reserve_frames(op, se, len, minframe, numdigits);
+               }
+               else {
+                       RNA_BEGIN (op->ptr, itemptr, "files")
+                       {
+                               char *filename = RNA_string_get_alloc(&itemptr, "name", NULL, 0);
+                               BLI_strncpy(se->name, filename, sizeof(se->name));
+                               MEM_freeN(filename);
+                               se++;
+                       }
+                       RNA_END;
                }
-               RNA_END;
 
                /* reset these else we wont see all the images */
                seq->anim_startofs = seq->anim_endofs = 0;
@@ -3736,6 +3808,16 @@ static int sequencer_change_path_exec(bContext *C, wmOperator *op)
                /* important else we don't get the imbuf cache flushed */
                BKE_sequencer_free_imbuf(scene, &ed->seqbase, false);
        }
+       else if (ELEM(seq->type, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) {
+               bSound *sound = seq->sound;
+               if (sound == NULL) {
+                       return OPERATOR_CANCELLED;
+               }
+               char filepath[FILE_MAX];
+               RNA_string_get(op->ptr, "filepath", filepath);
+               BLI_strncpy(sound->name, filepath, sizeof(sound->name));
+               BKE_sound_load(bmain, sound);
+       }
        else {
                /* lame, set rna filepath */
                PointerRNA seq_ptr;
@@ -3794,7 +3876,125 @@ void SEQUENCER_OT_change_path(struct wmOperatorType *ot)
        /* flags */
        ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
 
-       WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, FILE_OPENFILE,
-                                      WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILEPATH | WM_FILESEL_FILES,
-                                      FILE_DEFAULTDISPLAY);
+       WM_operator_properties_filesel(
+               ot, FILE_TYPE_FOLDER, FILE_SPECIAL, FILE_OPENFILE,
+               WM_FILESEL_DIRECTORY | WM_FILESEL_RELPATH | WM_FILESEL_FILEPATH | WM_FILESEL_FILES,
+               FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
+       RNA_def_boolean(ot->srna, "use_placeholders", false, "Use Placeholders", "Use placeholders for missing frames of the strip");
+}
+
+static int sequencer_export_subtitles_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+       if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+               char filepath[FILE_MAX];
+
+               if (G.main->name[0] == 0)
+                       BLI_strncpy(filepath, "untitled", sizeof(filepath));
+               else
+                       BLI_strncpy(filepath, G.main->name, sizeof(filepath));
+
+               BLI_replace_extension(filepath, sizeof(filepath), ".srt");
+               RNA_string_set(op->ptr, "filepath", filepath);
+       }
+
+       WM_event_add_fileselect(C, op);
+
+       return OPERATOR_RUNNING_MODAL;
+}
+
+static int sequencer_export_subtitles_exec(bContext *C, wmOperator *op)
+{
+       Scene *scene = CTX_data_scene(C);
+       Sequence *seq, *seq_next;
+       Editing *ed = BKE_sequencer_editing_get(scene, false);
+       ListBase text_seq = {0};
+       int iter = 0;
+       FILE *file;
+       char filepath[FILE_MAX];
+
+       if (!RNA_struct_property_is_set(op->ptr, "filepath")) {
+               BKE_report(op->reports, RPT_ERROR, "No filename given");
+               return OPERATOR_CANCELLED;
+       }
+
+       RNA_string_get(op->ptr, "filepath", filepath);
+       BLI_ensure_extension(filepath, sizeof(filepath), ".srt");
+
+       /* Avoid File write exceptions */
+       if (!BLI_exists(filepath)) {
+               BLI_make_existing_file(filepath);
+               if (!BLI_file_touch(filepath)) {
+                       BKE_report(op->reports, RPT_ERROR, "Can't create subtitle file");
+                       return OPERATOR_CANCELLED;
+               }
+       }
+       else if (!BLI_file_is_writable(filepath)) {
+               BKE_report(op->reports, RPT_ERROR, "Can't overwrite export file");
+               return OPERATOR_CANCELLED;
+       }
+
+       SEQ_BEGIN(ed, seq)
+       {
+               if (seq->type == SEQ_TYPE_TEXT) {
+                       BLI_addtail(&text_seq, MEM_dupallocN(seq));
+               }
+       }
+       SEQ_END
+
+       if (BLI_listbase_is_empty(&text_seq)) {
+               BKE_report(op->reports, RPT_ERROR, "No subtitles (text strips) to export");
+               return OPERATOR_CANCELLED;
+       }
+
+       BLI_listbase_sort(&text_seq, BKE_sequencer_cmp_time_startdisp);
+
+       /* time to open and write! */
+       file = BLI_fopen(filepath, "w");
+
+       for (seq = text_seq.first; seq; seq = seq_next) {
+               TextVars *data = seq->effectdata;
+               char timecode_str_start[32];
+               char timecode_str_end[32];
+
+               BLI_timecode_string_from_time(timecode_str_start, sizeof(timecode_str_start),
+                                             -2, FRA2TIME(seq->startdisp), FPS, USER_TIMECODE_SUBRIP);
+               BLI_timecode_string_from_time(timecode_str_end, sizeof(timecode_str_end),
+                                             -2, FRA2TIME(seq->enddisp), FPS, USER_TIMECODE_SUBRIP);
+
+               fprintf(file, "%d\n%s --> %s\n%s\n\n", iter++, timecode_str_start, timecode_str_end, data->text);
+
+               seq_next = seq->next;
+               MEM_freeN(seq);
+       }
+
+       fclose(file);
+
+       return OPERATOR_FINISHED;
+}
+
+static int sequencer_strip_is_text_poll(bContext *C)
+{
+       Editing *ed;
+       Sequence *seq;
+       return (((ed = BKE_sequencer_editing_get(CTX_data_scene(C), false)) != NULL) && ((seq = ed->act_seq) != NULL) && (seq->type == SEQ_TYPE_TEXT));
+}
+
+void SEQUENCER_OT_export_subtitles(struct wmOperatorType *ot)
+{
+       /* identifiers */
+       ot->name = "Export Subtitles";
+       ot->idname = "SEQUENCER_OT_export_subtitles";
+       ot->description = "Export .srt file containing text strips";
+
+       /* api callbacks */
+       ot->exec = sequencer_export_subtitles_exec;
+       ot->invoke = sequencer_export_subtitles_invoke;
+       ot->poll = sequencer_strip_is_text_poll;
+
+       /* flags */
+       ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+
+       WM_operator_properties_filesel(
+               ot,  FILE_TYPE_FOLDER, FILE_BLENDER, FILE_SAVE,
+               WM_FILESEL_FILEPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA);
 }