Cleanup: left wrong comment in
[blender-staging.git] / source / blender / editors / space_sequencer / sequencer_edit.c
index 8030efbf7565e6f90ab664b115c55a4ba343684b..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}
@@ -558,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");
@@ -666,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;
@@ -678,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;
@@ -696,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) {
@@ -715,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)) {
@@ -729,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;
@@ -740,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);
        }
@@ -762,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;
@@ -774,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;
@@ -792,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) {
@@ -808,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)) {
@@ -822,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;
@@ -925,37 +969,6 @@ 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);
-                               }
-                       }
-
-               }
-       }
-       SEQ_END
-
-       WM_cursor_wait(0);
-}
-
 #if 0
 static void set_filter_seq(Scene *scene)
 {
@@ -1203,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);
                }
@@ -1250,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";
        
@@ -1524,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)
@@ -1924,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);
@@ -1945,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)
@@ -2046,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}
@@ -2175,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;
@@ -2207,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 */
@@ -2217,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) {
@@ -2375,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);
@@ -2445,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 */
@@ -2505,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))
@@ -2707,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))
 {
@@ -2787,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));
 
@@ -2812,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", ""},
@@ -3189,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)
@@ -3256,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) {
@@ -3341,6 +3385,9 @@ static int sequencer_swap_data_exec(bContext *C, wmOperator *op)
        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);
 
        return OPERATOR_FINISHED;
@@ -3407,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 */
@@ -3498,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)) {
@@ -3534,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;
@@ -3566,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", ""},
@@ -3761,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;
@@ -3819,8 +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);
+}