rework undo compression, add shift viewer overwr/copy/clip/splice, fix paste edl...
[goodguy/history.git] / cinelerra-5.1 / cinelerra / mwindowedit.C
index a12321546dbd36aee6ce3c725e851ac211716e2c..b406c7b207f12c4d421eedb58e25b045e3292519 100644 (file)
@@ -74,6 +74,7 @@
 #include "vwindow.h"
 #include "vwindowgui.h"
 #include "zoombar.h"
+#include "zwindow.h"
 #include "automation.h"
 #include "maskautos.h"
 
@@ -96,8 +97,7 @@ void MWindow::add_audio_track_entry(int above, Track *dst)
 //     gui->cursor->draw(1);
 //     gui->canvas->flash();
 //     gui->canvas->activate();
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_EDL, edl, 1);
+       cwindow->refresh_frame(CHANGE_EDL);
 }
 
 void MWindow::add_video_track_entry(Track *dst)
@@ -116,8 +116,7 @@ void MWindow::add_video_track_entry(Track *dst)
 //     gui->cursor->draw(1);
 //     gui->canvas->flash();
 //     gui->canvas->activate();
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_EDL, edl, 1);
+       cwindow->refresh_frame(CHANGE_EDL);
        save_backup();
 }
 
@@ -137,8 +136,7 @@ void MWindow::add_subttl_track_entry(Track *dst)
 //     gui->cursor->draw(1);
 //     gui->canvas->flash();
 //     gui->canvas->activate();
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_EDL, edl, 1);
+       cwindow->refresh_frame(CHANGE_EDL);
        save_backup();
 }
 
@@ -196,7 +194,7 @@ void MWindow::asset_to_all()
                                edl->session->aspect_h,
                                w, h);
 
-                       for( Track *current = edl->tracks->first; current; current = NEXT ) {
+                       for( Track *current=edl->tracks->first; current; current=NEXT ) {
                                if( current->data_type == TRACK_VIDEO /* &&
                                        current->record */  ) {
                                        current->track_w = w;
@@ -311,8 +309,7 @@ void MWindow::clear_entry()
        update_plugin_guis();
        gui->update(1, 2, 1, 1, 1, 1, 0);
        cwindow->update(1, 0, 0, 0, 1);
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_EDL, edl, 1);
+       cwindow->refresh_frame(CHANGE_EDL);
 }
 
 void MWindow::clear(int clear_handle)
@@ -408,8 +405,7 @@ void MWindow::concatenate_tracks()
 
        restart_brender();
        gui->update(1, 1, 0, 0, 1, 0, 0);
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_EDL, edl, 1);
+       cwindow->refresh_frame(CHANGE_EDL);
 }
 
 
@@ -424,13 +420,11 @@ int MWindow::copy(double start, double end)
        if( start == end ) return 1;
 
        FileXML file;
-       edl->copy(start, end, 0, 0, 0, &file, "", 1);
+       edl->copy(start, end, 0, &file, "", 1);
        const char *file_string = file.string();
        long file_length = strlen(file_string);
-       gui->get_clipboard()->to_clipboard(file_string, file_length,
-               SECONDARY_SELECTION);
-       gui->get_clipboard()->to_clipboard(file_string, file_length,
-               BC_PRIMARY_SELECTION);
+       gui->to_clipboard(file_string, file_length, BC_PRIMARY_SELECTION);
+       gui->to_clipboard(file_string, file_length, SECONDARY_SELECTION);
        save_backup();
        return 0;
 }
@@ -443,10 +437,8 @@ int MWindow::copy_automation()
        edl->tracks->copy_automation(start, end, &file, 0, 1);
        const char *file_string = file.string();
        long file_length = strlen(file_string);
-       gui->get_clipboard()->to_clipboard(file_string, file_length,
-               BC_PRIMARY_SELECTION);
-       gui->get_clipboard()->to_clipboard(file_string, file_length,
-               SECONDARY_SELECTION);
+       gui->to_clipboard(file_string, file_length, BC_PRIMARY_SELECTION);
+       gui->to_clipboard(file_string, file_length, SECONDARY_SELECTION);
        return 0;
 }
 
@@ -458,10 +450,8 @@ int MWindow::copy_default_keyframe()
        edl->tracks->copy_automation(start, end, &file, 1, 0);
        const char *file_string = file.string();
        long file_length = strlen(file_string);
-       gui->get_clipboard()->to_clipboard(file_string, file_length,
-               BC_PRIMARY_SELECTION);
-       gui->get_clipboard()->to_clipboard(file_string, file_length,
-               SECONDARY_SELECTION);
+       gui->to_clipboard(file_string, file_length, BC_PRIMARY_SELECTION);
+       gui->to_clipboard(file_string, file_length, SECONDARY_SELECTION);
        return 0;
 }
 
@@ -511,35 +501,93 @@ void MWindow::crop_video()
        undo->update_undo_after(_("crop"), LOAD_ALL);
 
        restart_brender();
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_ALL, edl, 1);
+       cwindow->refresh_frame(CHANGE_ALL);
        save_backup();
 }
 
 void MWindow::cut()
 {
-       undo->update_undo_before();
-
        double start = edl->local_session->get_selectionstart();
        double end = edl->local_session->get_selectionend();
+       if( EQUIV(start,end) )
+               blade(start);
+       else
+               cut(start, end);
+}
 
+void MWindow::blade(double position)
+{
+       undo->update_undo_before();
+       edl->blade(position);
+       edl->optimize();
+       save_backup();
+       undo->update_undo_after(_("blade"), LOAD_EDITS | LOAD_TIMEBAR);
+       restart_brender();
+       update_plugin_guis();
+       gui->update(1, 2, 1, 1, 1, 1, 0);
+       cwindow->update(1, 0, 0, 0, 1);
+       awindow->gui->async_update_assets();
+       cwindow->refresh_frame(CHANGE_EDL);
+}
+
+void MWindow::cut(double start, double end, double new_position)
+{
+       undo->update_undo_before();
        copy(start, end);
        edl->clear(start, end,
                edl->session->labels_follow_edits,
                edl->session->plugins_follow_edits,
                edl->session->autos_follow_edits);
 
-
        edl->optimize();
        save_backup();
-       undo->update_undo_after(_("cut"), LOAD_EDITS | LOAD_TIMEBAR);
-
+       undo->update_undo_after(_("split | cut"), LOAD_EDITS | LOAD_TIMEBAR);
+       if( new_position >= 0 ) {
+               edl->local_session->set_selectionstart(new_position);
+               edl->local_session->set_selectionend(new_position);
+       }
        restart_brender();
        update_plugin_guis();
        gui->update(1, 2, 1, 1, 1, 1, 0);
        cwindow->update(1, 0, 0, 0, 1);
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_EDL, edl, 1);
+       awindow->gui->async_update_assets();
+       cwindow->refresh_frame(CHANGE_EDL);
+}
+
+void MWindow::cut_left_edit()
+{
+       double start_pos = edl->local_session->get_selectionstart(1);
+       double position = edl->prev_edit(start_pos);
+       if( position < start_pos )
+               cut(position, start_pos, position);
+}
+
+void MWindow::cut_right_edit()
+{
+       double end_pos = edl->local_session->get_selectionend(1);
+       double position = edl->next_edit(end_pos);
+       if( end_pos < position )
+               cut(end_pos, position, end_pos);
+}
+
+void MWindow::cut_left_label()
+{
+       double start_pos = edl->local_session->get_selectionstart(1);
+       Label *left_label = edl->labels->prev_label(start_pos);
+       if( !left_label ) return;
+       double position = left_label->position;
+       if( position < start_pos )
+               cut(position, start_pos, position);
+}
+
+void MWindow::cut_right_label()
+{
+       double end_pos = edl->local_session->get_selectionend(1);
+       Label *right_label = edl->labels->next_label(end_pos);
+       if( !right_label ) return;
+       double position = right_label->position;
+       if( end_pos < position )
+               cut(end_pos, position, end_pos);
 }
 
 int MWindow::cut_automation()
@@ -583,19 +631,6 @@ int MWindow::cut_default_keyframe()
 }
 
 
-void MWindow::delete_inpoint()
-{
-       edl->local_session->unset_inpoint();
-       save_backup();
-}
-
-void MWindow::delete_outpoint()
-{
-       edl->local_session->unset_outpoint();
-       save_backup();
-}
-
-
 void MWindow::delete_track()
 {
        if( edl->tracks->last )
@@ -613,8 +648,7 @@ void MWindow::delete_tracks()
        update_plugin_states();
 
        gui->update(1, 1, 1, 0, 1, 0, 0);
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_EDL, edl, 1);
+       cwindow->refresh_frame(CHANGE_EDL);
 }
 
 void MWindow::delete_track(Track *track)
@@ -627,8 +661,7 @@ void MWindow::delete_track(Track *track)
        update_plugin_states();
 
        gui->update(1, 1, 1, 0, 1, 0, 0);
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_EDL, edl, 1);
+       cwindow->refresh_frame(CHANGE_EDL);
        save_backup();
 }
 
@@ -682,7 +715,7 @@ void MWindow::insert_effects_canvas(double start,
 
        undo->update_undo_before();
 
-       for( int i = 0; i < session->drag_pluginservers->total; i++ ) {
+       for( int i=0; i<session->drag_pluginservers->total; ++i ) {
                PluginServer *plugin = session->drag_pluginservers->values[i];
                insert_effect(plugin->title, 0, dest_track,
                        i == 0 ? session->pluginset_highlighted : 0,
@@ -712,7 +745,7 @@ void MWindow::insert_effects_cwindow(Track *dest_track)
                        edl->local_session->get_selectionstart();
        }
 
-       for( int i = 0; i < session->drag_pluginservers->total; i++ ) {
+       for( int i=0; i<session->drag_pluginservers->total; ++i ) {
                PluginServer *plugin = session->drag_pluginservers->values[i];
                insert_effect(plugin->title, 0, dest_track, 0,
                        start, length, PLUGIN_STANDALONE);
@@ -735,7 +768,7 @@ void MWindow::insert_effect(char *title,
        SharedLocation shared_location_local;
        shared_location_local.copy_from(shared_location);
        int first_track = 1;
-       for( ; current; current = NEXT) {
+       for( ; current; current=NEXT ) {
                if( current->data_type == data_type &&
                        current->record ) {
                        insert_effect(title, &shared_location_local,
@@ -826,15 +859,18 @@ void MWindow::finish_modify_handles()
 
        if( (session->drag_handle == 1 && edit_mode != MOVE_NO_EDITS) ||
                (session->drag_handle == 0 && edit_mode == MOVE_ONE_EDIT) ) {
+//printf("MWindow::finish_modify_handles %d\n", __LINE__);
                edl->local_session->set_selectionstart(session->drag_position);
                edl->local_session->set_selectionend(session->drag_position);
        }
        else
        if( edit_mode != MOVE_NO_EDITS ) {
+//printf("MWindow::finish_modify_handles %d\n", __LINE__);
                edl->local_session->set_selectionstart(session->drag_start);
                edl->local_session->set_selectionend(session->drag_start);
        }
 
+// clamp the selection to 0
        if( edl->local_session->get_selectionstart(1) < 0 ) {
                edl->local_session->set_selectionstart(0);
                edl->local_session->set_selectionend(0);
@@ -846,6 +882,8 @@ void MWindow::finish_modify_handles()
        sync_parameters(CHANGE_EDL);
        update_plugin_guis();
        gui->update(1, 2, 1, 1, 1, 1, 0);
+// label list can be modified
+       awindow->gui->async_update_assets();
        cwindow->update(1, 0, 0, 0, 1);
 }
 
@@ -881,8 +919,7 @@ void MWindow::move_edits(ArrayList<Edit*> *edits,
        undo->update_undo_after(_("move edit"), LOAD_ALL);
 
        restart_brender();
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_EDL, edl, 1);
+       cwindow->refresh_frame(CHANGE_EDL);
 
        update_plugin_guis();
        gui->update(1, 1,      // 1 for incremental drawing.  2 for full refresh
@@ -897,8 +934,7 @@ void MWindow::move_effect(Plugin *plugin, Track *track, int64_t position)
        undo->update_undo_after(_("paste effect"), LOAD_ALL);
 
        restart_brender();
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_EDL, edl, 1); 
+       cwindow->refresh_frame(CHANGE_EDL);
        update_plugin_guis();
        gui->update(1, 1,      // 1 for incremental drawing.  2 for full refresh
                0, 0, 0, 0, 0);
@@ -912,8 +948,7 @@ void MWindow::move_effect(Plugin *plugin, PluginSet *plugin_set, int64_t positio
        undo->update_undo_after(_("move effect"), LOAD_ALL);
 
        restart_brender();
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_EDL, edl, 1);
+       cwindow->refresh_frame(CHANGE_EDL);
        update_plugin_guis();
        gui->update(1, 1,      // 1 for incremental drawing.  2 for full refresh
                0, 0, 0, 0, 0);
@@ -1011,24 +1046,26 @@ void MWindow::mute_selection()
                edl->paste_silence(start, end, 0,
                        edl->session->plugins_follow_edits,
                        edl->session->autos_follow_edits);
+
                save_backup();
                undo->update_undo_after(_("mute"), LOAD_EDITS);
 
                restart_brender();
                update_plugin_guis();
                gui->update(1, 2, 1, 1, 1, 1, 0);
-               cwindow->playback_engine->que->
-                       send_command(CURRENT_FRAME, CHANGE_EDL, edl, 1);
+               cwindow->refresh_frame(CHANGE_EDL);
        }
 }
 
 
-void MWindow::overwrite(EDL *source)
+void MWindow::overwrite(EDL *source, int all)
 {
        FileXML file;
 
-       double src_start = source->local_session->get_selectionstart();
-       double overwrite_len = source->local_session->get_selectionend() - src_start;
+       double src_start = all ? 0 :
+               source->local_session->get_selectionstart();
+       double overwrite_len = all ? source->tracks->total_length() :
+               source->local_session->get_selectionend() - src_start;
        double dst_start = edl->local_session->get_selectionstart();
        double dst_len = edl->local_session->get_selectionend() - dst_start;
 
@@ -1039,8 +1076,7 @@ void MWindow::overwrite(EDL *source)
                overwrite_len = dst_len;
        }
 
-       source->copy(src_start, src_start + overwrite_len,
-               1, 0, 0, &file, "", 1);
+       source->copy(src_start, src_start + overwrite_len, 0, &file, "", 1);
 
 // HACK around paste_edl get_start/endselection on its own
 // so we need to clear only when not using both io points
@@ -1087,12 +1123,12 @@ void MWindow::paste()
 {
        double start = edl->local_session->get_selectionstart();
        //double end = edl->local_session->get_selectionend();
-       int64_t len = gui->get_clipboard()->clipboard_len(SECONDARY_SELECTION);
+       int64_t len = gui->clipboard_len(BC_PRIMARY_SELECTION);
 
        if( len ) {
-               char *string = new char[len + 1];
+               char *string = new char[len];
                undo->update_undo_before();
-               gui->get_clipboard()->from_clipboard(string, len, BC_PRIMARY_SELECTION);
+               gui->from_clipboard(string, len, BC_PRIMARY_SELECTION);
                FileXML file;
                file.read_from_string(string);
                clear(0);
@@ -1153,21 +1189,17 @@ int MWindow::paste_assets(double position, Track *dest_track, int overwrite)
 }
 
 void MWindow::load_assets(ArrayList<Indexable*> *new_assets,
-       double position,
-       int load_mode,
-       Track *first_track,
-       RecordLabels *labels,
-       int edit_labels,
-       int edit_plugins,
-       int edit_autos,
-       int overwrite)
+       double position, int load_mode, Track *first_track, RecordLabels *labels,
+       int edit_labels, int edit_plugins, int edit_autos, int overwrite)
 {
+       if( load_mode == LOADMODE_RESOURCESONLY )
+               load_mode = LOADMODE_ASSETSONLY;
 const int debug = 0;
 if( debug ) printf("MWindow::load_assets %d\n", __LINE__);
        if( position < 0 ) position = edl->local_session->get_selectionstart();
 
        ArrayList<EDL*> new_edls;
-       for( int i = 0; i < new_assets->total; i++ ) {
+       for( int i=0; i<new_assets->total; ++i ) {
                Indexable *indexable = new_assets->get(i);
                if( indexable->is_asset ) {
                        remove_asset_from_caches((Asset*)indexable);
@@ -1177,19 +1209,18 @@ if( debug ) printf("MWindow::load_assets %d\n", __LINE__);
                new_edl->copy_session(edl);
                new_edls.append(new_edl);
 
-
-               if( indexable->is_asset ) {
-if( debug ) printf("MWindow::load_assets %d\n", __LINE__);
-if( debug ) ((Asset*)indexable)->dump();
-                       asset_to_edl(new_edl, (Asset*)indexable);
+               if( !indexable->is_asset ) {
+                       EDL *nested_edl = (EDL*)indexable;
+                       new_edl->to_nested(nested_edl);
+                       new_edl->local_session->set_clip_path(nested_edl);
+               }
+               else {
+                       Asset *asset = (Asset*)indexable;
+                       asset_to_edl(new_edl, asset);
                }
-               else
-                       edl_to_nested(new_edl, (EDL*)indexable);
-if( debug ) printf("MWindow::load_assets %d\n", __LINE__);
-
 
                if( labels ) {
-                       for( RecordLabel *label = labels->first; label; label = label->next ) {
+                       for( RecordLabel *label=labels->first; label; label=label->next ) {
                                new_edl->labels->toggle_label(label->position, label->position);
                        }
                }
@@ -1201,7 +1232,7 @@ if( debug ) printf("MWindow::load_assets %d\n", __LINE__);
 if( debug ) printf("MWindow::load_assets %d\n", __LINE__);
 
        save_backup();
-       for( int i = 0; i < new_edls.size(); i++ )
+       for( int i=0; i<new_edls.size(); ++i )
                new_edls.get(i)->Garbage::remove_user();
 
 if( debug ) printf("MWindow::load_assets %d\n", __LINE__);
@@ -1209,14 +1240,12 @@ if( debug ) printf("MWindow::load_assets %d\n", __LINE__);
 
 int MWindow::paste_automation()
 {
-       int64_t len = gui->get_clipboard()->clipboard_len(SECONDARY_SELECTION);
+       int64_t len = gui->clipboard_len(BC_PRIMARY_SELECTION);
 
        if( len ) {
                undo->update_undo_before();
-               char *string = new char[len + 1];
-               gui->get_clipboard()->from_clipboard(string,
-                       len,
-                       BC_PRIMARY_SELECTION);
+               char *string = new char[len];
+               gui->from_clipboard(string, len, BC_PRIMARY_SELECTION);
                FileXML file;
                file.read_from_string(string);
 
@@ -1242,14 +1271,12 @@ int MWindow::paste_automation()
 
 int MWindow::paste_default_keyframe()
 {
-       int64_t len = gui->get_clipboard()->clipboard_len(SECONDARY_SELECTION);
+       int64_t len = gui->clipboard_len(BC_PRIMARY_SELECTION);
 
        if( len ) {
                undo->update_undo_before();
-               char *string = new char[len + 1];
-               gui->get_clipboard()->from_clipboard(string,
-                       len,
-                       BC_PRIMARY_SELECTION);
+               char *string = new char[len];
+               gui->from_clipboard(string, len, BC_PRIMARY_SELECTION);
                FileXML file;
                file.read_from_string(string);
                double start = edl->local_session->get_selectionstart();
@@ -1286,7 +1313,7 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
        if( !new_edls->total ) return 0;
 
 //PRINT_TRACE
-//     double original_length = edl->tracks->total_playable_length();
+//     double original_length = edl->tracks->total_length();
 //     double original_preview_end = edl->local_session->preview_end;
 //PRINT_TRACE
 
@@ -1300,6 +1327,7 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
                edl = new EDL;
                edl->create_objects();
                edl->copy_session(new_edls->values[0]);
+               edl->copy_mixers(new_edls->values[0]);
                gui->mainmenu->update_toggles(0);
                gui->unlock_window();
                gwindow->gui->update_toggles(1);
@@ -1323,33 +1351,30 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
            load_mode == LOADMODE_NEW_TRACKS ) {
 
                need_new_tracks = 1;
-               for( int i = 0; i < new_edls->total; i++ ) {
+               for( int i=0; i<new_edls->total; ++i ) {
                        EDL *new_edl = new_edls->values[i];
-                       for( Track *current = new_edl->tracks->first;
-                               current;
-                               current = NEXT ) {
-                               if( current->data_type == TRACK_VIDEO ) {
+                       for( Track *current=new_edl->tracks->first; current; current=NEXT ) {
+                               switch( current->data_type ) {
+                               case TRACK_VIDEO:
                                        edl->tracks->add_video_track(0, 0);
                                        if( current->draw ) edl->tracks->last->draw = 1;
-                                       destination_tracks.append(edl->tracks->last);
-                               }
-                               else
-                               if( current->data_type == TRACK_AUDIO ) {
+                                       break;
+                               case TRACK_AUDIO:
                                        edl->tracks->add_audio_track(0, 0);
-                                       destination_tracks.append(edl->tracks->last);
-                               }
-                               else
-                               if( current->data_type == TRACK_SUBTITLE ) {
+                                       break;
+                               case TRACK_SUBTITLE:
                                        edl->tracks->add_subttl_track(0, 0);
-                                       destination_tracks.append(edl->tracks->last);
+                                       break;
+                               default:
+                                       continue;
                                }
-                               edl->session->highlighted_track = edl->tracks->total() - 1;
+                               destination_tracks.append(edl->tracks->last);
                        }
 
 // Base track count on first EDL only for concatenation
                        if( load_mode == LOADMODE_REPLACE_CONCATENATE ) break;
                }
-
+               edl->session->highlighted_track = edl->tracks->total() - 1;
        }
        else
 // Recycle existing tracks of master EDL
@@ -1362,13 +1387,12 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
 // then be shifted back to their original locations without recursively
 // shifting back every paste.
                if( (load_mode == LOADMODE_PASTE || load_mode == LOADMODE_NESTED) &&
-                       edl->session->labels_follow_edits )
+                   edl->session->labels_follow_edits )
                        edl->labels->clear(edl->local_session->get_selectionstart(),
-                                               edl->local_session->get_selectionend(),
-                                               1);
+                                          edl->local_session->get_selectionend(), 1);
 
                Track *current = first_track ? first_track : edl->tracks->first;
-               for( ; current; current = NEXT) {
+               for( ; current; current=NEXT ) {
                        if( current->record ) {
                                destination_tracks.append(current);
                        }
@@ -1381,7 +1405,7 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
        double *paste_position = new double[destination_tracks.total];
 
 // Iterate through the edls
-       for( int i = 0; i < new_edls->total; i++ ) {
+       for( int i=0; i<new_edls->total; ++i ) {
 
                EDL *new_edl = new_edls->values[i];
                double edl_length = new_edl->local_session->clipboard_length ?
@@ -1402,9 +1426,8 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
                        TRACK_VIDEO);
 //PRINT_TRACE
 // Add assets and prepare index files
-               for( Asset *new_asset = new_edl->assets->first;
-                    new_asset;
-                    new_asset = new_asset->next ) {
+               for( Asset *new_asset=new_edl->assets->first;
+                    new_asset; new_asset=new_asset->next ) {
                        mainindexes->add_next_asset(0, new_asset);
                }
 // Capture index file status from mainindex test
@@ -1430,7 +1453,7 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
                case LOADMODE_NESTED:
                        destination_track = 0;
                        if( i == 0 ) {
-                               for( int j = 0; j < destination_tracks.total; j++ ) {
+                               for( int j=0; j<destination_tracks.total; ++j ) {
                                        paste_position[j] = (current_position >= 0) ?
                                                current_position :
                                                edl->local_session->get_selectionstart();
@@ -1444,7 +1467,8 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
                }
 //PRINT_TRACE
 // Insert edl
-               if( load_mode != LOADMODE_RESOURCESONLY ) {
+               if( load_mode != LOADMODE_RESOURCESONLY &&
+                   load_mode != LOADMODE_ASSETSONLY ) {
 // Insert labels
 //printf("MWindow::paste_edls %f %f\n", current_position, edl_length);
                        if( load_mode == LOADMODE_PASTE ||
@@ -1460,14 +1484,13 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
                                        edit_labels);
 //PRINT_TRACE
 
-                       for( Track *new_track = new_edl->tracks->first;
-                            new_track;
-                            new_track = new_track->next ) {
+                       for( Track *new_track=new_edl->tracks->first;
+                            new_track; new_track=new_track->next ) {
 // Get destination track of same type as new_track
                                for( int k = 0;
-                                       k < destination_tracks.total &&
-                                       destination_tracks.values[destination_track]->data_type != new_track->data_type;
-                                       k++, destination_track++ ) {
+                                    k < destination_tracks.total &&
+                                    destination_tracks.values[destination_track]->data_type != new_track->data_type;
+                                    ++k, ++destination_track ) {
                                        if( destination_track >= destination_tracks.total - 1 )
                                                destination_track = 0;
                                }
@@ -1529,11 +1552,14 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
 // strange issue, for index not being shown
 // Assume any paste operation from the same EDL won't contain any clips.
 // If it did it would duplicate every clip here.
-       for( int i = 0; i < new_edls->total; i++ ) {
-               EDL *new_edl = new_edls->values[i];
+       for( int i=0; i<new_edls->total; ++i ) {
+               EDL *new_edl = new_edls->get(i);
 
-               for( int j = 0; j < new_edl->clips.total; j++ ) {
-                       edl->add_clip(new_edl->clips.values[j]);
+               for( int j=0; j<new_edl->clips.size(); ++j ) {
+                       edl->add_clip(new_edl->clips[j]);
+               }
+               for( int j=0; j<new_edl->nested_edls.size(); ++j ) {
+                       edl->nested_edls.get_copy(new_edl->nested_edls[j]);
                }
 
                if( new_edl->total_vwindow_edls() ) {
@@ -1543,7 +1569,7 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
 //                     edl->vwindow_edl->create_objects();
 //                     edl->vwindow_edl->copy_all(new_edl->vwindow_edl);
 
-                       for( int j = 0; j < new_edl->total_vwindow_edls(); j++ ) {
+                       for( int j=0; j<new_edl->total_vwindow_edls(); ++j ) {
                                EDL *vwindow_edl = new EDL(edl);
                                vwindow_edl->create_objects();
                                vwindow_edl->copy_all(new_edl->get_vwindow_edl(j));
@@ -1560,7 +1586,7 @@ int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
 // Fix preview range
 //     if( EQUIV(original_length, original_preview_end) )
 //     {
-//             edl->local_session->preview_end = edl->tracks->total_playable_length();
+//             edl->local_session->preview_end = edl->tracks->total_length();
 //     }
 
 // Start examining next batch of index files
@@ -1588,8 +1614,7 @@ void MWindow::paste_silence()
        restart_brender();
        gui->update(1, 2, 1, 1, 1, 1, 0);
        cwindow->update(1, 0, 0, 0, 1);
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_EDL, edl, 1);
+       cwindow->refresh_frame(CHANGE_EDL);
 }
 
 void MWindow::detach_transition(Transition *transition)
@@ -1832,47 +1857,34 @@ void MWindow::set_transition_length(double length)
 
 void MWindow::redo_entry(BC_WindowBase *calling_window_gui)
 {
-
        calling_window_gui->unlock_window();
+       stop_playback(0);
+       if( undo->redo_load_flags() & LOAD_SESSION )
+               close_mixers();
 
-       cwindow->playback_engine->que->
-               send_command(STOP, CHANGE_NONE, 0, 0);
-       cwindow->playback_engine->interrupt_playback(0);
-
-       for( int i = 0; i < vwindows.size(); i++ ) {
-               if( vwindows.get(i)->is_running() ) {
-                       vwindows.get(i)->playback_engine->que->
-                               send_command(STOP, CHANGE_NONE, 0, 0);
-                       vwindows.get(i)->playback_engine->interrupt_playback(0);
-               }
-       }
-
-       cwindow->gui->lock_window("MWindow::redo_entry");
-       for( int i = 0; i < vwindows.size(); i++ ) {
+       cwindow->gui->lock_window("MWindow::redo_entry 1");
+       for( int i=0; i<vwindows.size(); ++i ) {
                if( vwindows.get(i)->is_running() ) {
                        if( calling_window_gui != vwindows.get(i)->gui ) {
                                vwindows.get(i)->gui->lock_window("MWindow::redo_entry 2");
                        }
                }
        }
-       gui->lock_window();
+       gui->lock_window("MWindow::redo_entry 3");
 
        undo->redo();
 
        save_backup();
+       restart_brender();
        update_plugin_states();
        update_plugin_guis();
-       restart_brender();
+
        gui->update(1, 2, 1, 1, 1, 1, 1);
+       gui->unlock_window();
        cwindow->update(1, 1, 1, 1, 1);
+       cwindow->gui->unlock_window();
 
-       if( calling_window_gui != cwindow->gui )
-               cwindow->gui->unlock_window();
-       if( calling_window_gui != gui )
-               gui->unlock_window();
-
-
-       for( int i = 0; i < vwindows.size(); i++ ) {
+       for( int i=0; i < vwindows.size(); ++i ) {
                if( vwindows.get(i)->is_running() ) {
                        if( calling_window_gui != vwindows.get(i)->gui ) {
                                vwindows.get(i)->gui->unlock_window();
@@ -1880,8 +1892,13 @@ void MWindow::redo_entry(BC_WindowBase *calling_window_gui)
                }
        }
 
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_ALL, edl, 1);
+       if( calling_window_gui != gui )
+               gui->unlock_window();
+
+       awindow->gui->async_update_assets();
+
+       cwindow->refresh_frame(CHANGE_ALL);
+       calling_window_gui->lock_window("MWindow::redo_entry 4");
 }
 
 
@@ -1950,14 +1967,40 @@ void MWindow::set_outpoint(int is_mwindow)
        }
 }
 
-void MWindow::splice(EDL *source)
+void MWindow::unset_inoutpoint(int is_mwindow)
+{
+       undo->update_undo_before();
+       edl->unset_inoutpoint();
+       save_backup();
+       undo->update_undo_after(_("clear in/out"), LOAD_TIMEBAR);
+
+       if( !is_mwindow ) {
+               gui->lock_window("MWindow::unset_inoutpoint 1");
+       }
+       gui->update_timebar(1);
+       if( !is_mwindow ) {
+               gui->unlock_window();
+       }
+
+       if( is_mwindow ) {
+               cwindow->gui->lock_window("MWindow::unset_inoutpoint 2");
+       }
+       cwindow->gui->timebar->update(1);
+       if( is_mwindow ) {
+               cwindow->gui->unlock_window();
+       }
+}
+
+void MWindow::splice(EDL *source, int all)
 {
        FileXML file;
 
        undo->update_undo_before();
-       double source_start = source->local_session->get_selectionstart();
-       double source_end = source->local_session->get_selectionend();
-       source->copy(source_start, source_end, 1, 0, 0, &file, "", 1);
+       double source_start = all ? 0 :
+               source->local_session->get_selectionstart();
+       double source_end = all ? source->tracks->total_length() :
+               source->local_session->get_selectionend();
+       source->copy(source_start, source_end, 1, &file, "", 1);
 //file.dump();
        double start = edl->local_session->get_selectionstart();
        //double end = edl->local_session->get_selectionend();
@@ -2004,7 +2047,7 @@ void MWindow::save_clip(EDL *new_edl, const char *txt)
        }
 
         time_t now;  time(&now);
-        struct tm *tm = localtime(&now);
+        struct tm dtm;   localtime_r(&now, &dtm);
        char *cp = new_edl->local_session->clip_notes;
        int n, sz = sizeof(new_edl->local_session->clip_notes)-1;
        if( txt && *txt ) {
@@ -2013,8 +2056,8 @@ void MWindow::save_clip(EDL *new_edl, const char *txt)
        }
        n = snprintf(cp, sz, 
                "%02d/%02d/%02d %02d:%02d:%02d,  +%s\n",
-               tm->tm_year+1900, tm->tm_mon+1, tm->tm_mday, 
-               tm->tm_hour, tm->tm_min, tm->tm_sec, duration);
+               dtm.tm_year+1900, dtm.tm_mon+1, dtm.tm_mday, 
+               dtm.tm_hour, dtm.tm_min, dtm.tm_sec, duration);
        cp += n;  sz -= n;
        if( path && *path ) {
                FileSystem fs;
@@ -2024,26 +2067,32 @@ void MWindow::save_clip(EDL *new_edl, const char *txt)
                cp += n;  sz -= n;
        }
        cp[n] = 0;
-
+       sprintf(new_edl->local_session->clip_icon,
+               "clip_%02d%02d%02d-%02d%02d%02d.png",
+               dtm.tm_year+1900, dtm.tm_mon+1, dtm.tm_mday,
+               dtm.tm_hour, dtm.tm_min, dtm.tm_sec);
        edl->update_assets(new_edl);
        int cur_x, cur_y;
-       gui->get_abs_cursor_xy(cur_x, cur_y, 0);
+       gui->get_abs_cursor(cur_x, cur_y, 0);
        gui->unlock_window();
 
        awindow->clip_edit->create_clip(new_edl, cur_x, cur_y);
+       new_edl->remove_user();
 
        gui->lock_window("MWindow::save_clip");
        save_backup();
 }
 
-void MWindow::to_clip(EDL *edl, const char *txt)
+void MWindow::to_clip(EDL *edl, const char *txt, int all)
 {
        FileXML file;
        double start, end;
 
        gui->lock_window("MWindow::to_clip 1");
-       start = edl->local_session->get_selectionstart();
-       end = edl->local_session->get_selectionend();
+       start = all ? 0 :
+               edl->local_session->get_selectionstart();
+       end = all ? edl->tracks->total_length() :
+               edl->local_session->get_selectionend();
 
        if( EQUIV(end, start) ) {
                start = 0;
@@ -2051,7 +2100,7 @@ void MWindow::to_clip(EDL *edl, const char *txt)
        }
 
 // Don't copy all since we don't want the clips twice.
-       edl->copy(start, end, 0, 0, 0, &file, "", 1);
+       edl->copy(start, end, 0, &file, "", 1);
 
        EDL *new_edl = new EDL(edl);
        new_edl->create_objects();
@@ -2122,31 +2171,21 @@ void MWindow::trim_selection()
        update_plugin_guis();
        gui->update(1, 2, 1, 1, 1, 1, 0);
        cwindow->update(1, 0, 0, 0, 1);
+       awindow->gui->async_update_assets();
        restart_brender();
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_EDL, edl, 1);
+       cwindow->refresh_frame(CHANGE_EDL);
 }
 
 
 void MWindow::undo_entry(BC_WindowBase *calling_window_gui)
 {
        calling_window_gui->unlock_window();
-
-       cwindow->playback_engine->que->
-               send_command(STOP, CHANGE_NONE, 0, 0);
-       cwindow->playback_engine->interrupt_playback(0);
-
-//printf("MWindow::undo_entry %d %d\n", __LINE__, vwindows.size());
-       for( int i = 0; i < vwindows.size(); i++ ) {
-               if( vwindows.get(i)->is_running() ) {
-                       vwindows.get(i)->playback_engine->que->
-                               send_command(STOP, CHANGE_NONE, 0, 0);
-                       vwindows.get(i)->playback_engine->interrupt_playback(0);
-               }
-       }
+       stop_playback(0);
+       if( undo->undo_load_flags() & LOAD_SESSION )
+               close_mixers();
 
        cwindow->gui->lock_window("MWindow::undo_entry 1");
-       for( int i = 0; i < vwindows.size(); i++ ) {
+       for( int i=0; i<vwindows.size(); ++i ) {
                if( vwindows.get(i)->is_running() ) {
                        if( calling_window_gui != vwindows.get(i)->gui ) {
                                vwindows.get(i)->gui->lock_window("MWindow::undo_entry 4");
@@ -2167,7 +2206,7 @@ void MWindow::undo_entry(BC_WindowBase *calling_window_gui)
        cwindow->update(1, 1, 1, 1, 1);
        cwindow->gui->unlock_window();
 
-       for( int i = 0; i < vwindows.size(); i++ ) {
+       for( int i=0; i<vwindows.size(); ++i ) {
                if( vwindows.get(i)->is_running() ) {
                        if( calling_window_gui != vwindows.get(i)->gui ) {
                                vwindows.get(i)->gui->unlock_window();
@@ -2180,8 +2219,7 @@ void MWindow::undo_entry(BC_WindowBase *calling_window_gui)
 
        awindow->gui->async_update_assets();
 
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_ALL, edl, 1);
+       cwindow->refresh_frame(CHANGE_ALL);
        calling_window_gui->lock_window("MWindow::undo_entry 4");
 }
 
@@ -2236,13 +2274,13 @@ void MWindow::remap_audio(int pattern)
 {
        int current_channel = 0;
        int current_track = 0;
-       for( Track *current = edl->tracks->first; current; current = NEXT ) {
+       for( Track *current=edl->tracks->first; current; current=NEXT ) {
                if( current->data_type == TRACK_AUDIO &&
                        current->record ) {
                        Autos *pan_autos = current->automation->autos[AUTOMATION_PAN];
                        PanAuto *pan_auto = (PanAuto*)pan_autos->get_auto_for_editing(-1);
 
-                       for( int i = 0; i < MAXCHANNELS; i++ ) {
+                       for( int i=0; i < MAXCHANNELS; ++i ) {
                                pan_auto->values[i] = 0.0;
                        }
 
@@ -2253,22 +2291,15 @@ void MWindow::remap_audio(int pattern)
                        if( pattern == MWindow::AUDIO_5_1_TO_2 ) {
                                switch( current_track ) {
                                case 0:
-                                       pan_auto->values[0] = 0.5;
-                                       pan_auto->values[1] = 0.5;
-                                       break;
-                               case 1:
+                               case 4:
                                        pan_auto->values[0] = 1;
                                        break;
-                               case 2:
+                               case 1:
+                               case 5:
                                        pan_auto->values[1] = 1;
                                        break;
+                               case 2:
                                case 3:
-                                       pan_auto->values[0] = 1;
-                                       break;
-                               case 4:
-                                       pan_auto->values[1] = 1;
-                                       break;
-                               case 5:
                                        pan_auto->values[0] = 0.5;
                                        pan_auto->values[1] = 0.5;
                                        break;
@@ -2287,6 +2318,100 @@ void MWindow::remap_audio(int pattern)
        }
 }
 
+void MWindow::set_proxy(int use_scaler, int new_scale, int auto_scale,
+               ArrayList<Indexable*> *orig_assets,
+               ArrayList<Indexable*> *proxy_assets)
+{
+       int orig_use_scaler = edl->session->proxy_use_scaler;
+       int orig_scale = edl->session->proxy_scale;
+// rescale to full size asset in read_frame
+       edl->session->proxy_use_scaler = use_scaler;
+       edl->session->proxy_scale = new_scale;
+       edl->session->proxy_auto_scale = auto_scale;
+
+       if( use_scaler ) {
+               for( int i=0; i<proxy_assets->size(); ++i ) {
+                       Asset *proxy_asset = (Asset *)proxy_assets->get(i);
+                       proxy_asset->width = orig_assets->get(i)->get_w();
+                       proxy_asset->height = orig_assets->get(i)->get_h();
+               }
+               new_scale = 1;
+       }
+
+       if( !orig_use_scaler && new_scale != orig_scale ) {
+// project size
+               float orig_w = (float)edl->session->output_w * orig_scale;
+               float orig_h = (float)edl->session->output_h * orig_scale;
+               edl->session->output_w = Units::round(orig_w / new_scale);
+               edl->session->output_h = Units::round(orig_h / new_scale);
+
+// track sizes
+               for( Track *track=edl->tracks->first; track; track=track->next ) {
+                       if( track->data_type != TRACK_VIDEO ) continue;
+                       orig_w = (float)track->track_w * orig_scale;
+                       orig_h = (float)track->track_h * orig_scale;
+                       track->track_w = Units::round(orig_w / new_scale);
+                       track->track_h = Units::round(orig_h / new_scale);
+                       ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->
+                               set_proxy(orig_scale, new_scale);
+                       ((FloatAutos*)track->automation->autos[AUTOMATION_CAMERA_X])->
+                               set_proxy(orig_scale, new_scale);
+                       ((FloatAutos*)track->automation->autos[AUTOMATION_CAMERA_Y])->
+                               set_proxy(orig_scale, new_scale);
+                       ((FloatAutos*)track->automation->autos[AUTOMATION_PROJECTOR_X])->
+                               set_proxy(orig_scale, new_scale);
+                       ((FloatAutos*)track->automation->autos[AUTOMATION_PROJECTOR_Y])->
+                               set_proxy(orig_scale, new_scale);
+               }
+       }
+
+// change original assets to proxy assets
+       int awindow_folder = use_scaler || new_scale != 1 ? AW_PROXY_FOLDER : AW_MEDIA_FOLDER;
+       for( int i=0,n=proxy_assets->size(); i<n; ++i ) {
+               Asset *proxy_asset = edl->assets->update((Asset *)proxy_assets->get(i));
+               proxy_asset->awindow_folder = awindow_folder;
+// replace track contents
+               for( Track *track=edl->tracks->first; track; track=track->next ) {
+                       if( track->data_type != TRACK_VIDEO ) continue;
+                       for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
+                               if( !edit->asset ) continue;
+                               if( !strcmp(edit->asset->path, orig_assets->get(i)->path) ) {
+                                       edit->asset = proxy_asset;
+                               }
+                       }
+               }
+       }
+}
+
+void MWindow::add_proxy(int use_scaler,
+               ArrayList<Indexable*> *orig_assets,
+               ArrayList<Indexable*> *proxy_assets)
+{
+       if( use_scaler ) {
+               for( int i=0,n=proxy_assets->size(); i<n; ++i ) {
+                       Asset *proxy_asset = (Asset *)proxy_assets->get(i);
+                       proxy_asset->width = orig_assets->get(i)->get_w();
+                       proxy_asset->height = orig_assets->get(i)->get_h();
+               }
+       }
+
+// change original assets to proxy assets
+       for( int i=0,n=proxy_assets->size(); i<n; ++i ) {
+               Asset *proxy_asset = edl->assets->update((Asset *)proxy_assets->get(i));
+               proxy_asset->awindow_folder = AW_PROXY_FOLDER;
+// replace track contents
+               for( Track *track=edl->tracks->first; track; track=track->next ) {
+                       if( track->data_type != TRACK_VIDEO ) continue;
+                       for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
+                               if( !edit->asset ) continue;
+                               if( !strcmp(edit->asset->path, orig_assets->get(i)->path) ) {
+                                       edit->asset = proxy_asset;
+                               }
+                       }
+               }
+       }
+}
+
 void MWindow::cut_commercials()
 {
        undo->update_undo_before();
@@ -2299,8 +2424,7 @@ void MWindow::cut_commercials()
        update_plugin_guis();
        gui->update(1, 2, 1, 1, 1, 1, 0);
        cwindow->update(1, 0, 0, 0, 1);
-       cwindow->playback_engine->que->
-               send_command(CURRENT_FRAME, CHANGE_EDL, edl, 1);
+       cwindow->refresh_frame(CHANGE_EDL);
 }