vicon drag tweaks, proxy drag fix, vicon mouseover, binfolder around sort fix, draw_r...
[goodguy/history.git] / cinelerra-5.1 / cinelerra / edl.C
index 49d4cecfc72a14b6197c6eef62e887b8ad09ec9a..2f0d6e20a78bed8b53f780f8d4788f6f2c53cbb0 100644 (file)
 #include "atrack.h"
 #include "autoconf.h"
 #include "automation.h"
-#include "awindowgui.inc"
+#include "awindowgui.h"
+#include "bccmodels.h"
+#include "bchash.h"
 #include "bcsignals.h"
 #include "clip.h"
 #include "cstrdup.h"
-#include "bccmodels.h"
-#include "bchash.h"
 #include "clipedls.h"
 #include "edits.h"
 #include "edl.h"
 #include "edlsession.h"
 #include "filexml.h"
+#include "floatauto.h"
+#include "floatautos.h"
 #include "guicast.h"
 #include "indexstate.h"
 #include "interlacemodes.h"
@@ -68,7 +70,6 @@ EDL::EDL(EDL *parent_edl)
        tracks = 0;
        labels = 0;
        local_session = 0;
-       folders.set_array_delete();
        id = next_id();
        path[0] = 0;
 }
@@ -85,7 +86,6 @@ EDL::~EDL()
                delete assets;
                delete session;
        }
-       folders.remove_all_objects();
 }
 
 
@@ -144,9 +144,7 @@ int EDL::create_default_tracks()
 int EDL::load_xml(FileXML *file, uint32_t load_flags)
 {
        int result = 0;
-
-// Clear objects
-       folders.remove_all_objects();
+       folders.clear();
 
        if( (load_flags & LOAD_ALL) == LOAD_ALL ) {
                remove_vwindow_edls();
@@ -235,10 +233,8 @@ int EDL::read_xml(FileXML *file, uint32_t load_flags)
                                        result = file->skip_tag();
                        }
                        else
-                       if( file->tag.title_is("FOLDER") ) {
-                               char folder[BCTEXTLEN];
-                               strcpy(folder, file->read_text());
-                               new_folder(folder);
+                       if( file->tag.title_is("FOLDERS") ) {
+                               result = folders.load_xml(file);
                        }
                        else
                        if( file->tag.title_is("MIXERS") ) {
@@ -298,7 +294,7 @@ int EDL::read_xml(FileXML *file, uint32_t load_flags)
                                nested_edl->create_objects();
                                nested_edl->read_xml(file, LOAD_ALL);
                                if( (load_flags & LOAD_ALL) == LOAD_ALL )
-                                       nested_edls.add_clip(nested_edl);
+                                       nested_edls.get_nested(nested_edl);
                                nested_edl->remove_user();
                        }
                        else
@@ -339,7 +335,7 @@ int EDL::read_xml(FileXML *file, uint32_t load_flags)
 // The string is not terminated in this call.
 int EDL::save_xml(FileXML *file, const char *output_path)
 {
-       copy(0, tracks->total_length(), 1, file, output_path, 0);
+       copy(1, file, output_path, 0);
        return 0;
 }
 
@@ -406,11 +402,8 @@ void EDL::copy_session(EDL *edl, int session_only)
 
        if( !session_only ) {
                strcpy(this->path, edl->path);
-//printf("EDL::copy_session %p %s\n", this, this->path);
-
-               folders.remove_all_objects();
-               for( int i=0; i<edl->folders.size(); ++i )
-                       folders.append(cstrdup(edl->folders[i]));
+               awindow_folder = edl->awindow_folder;
+               folders.copy_from(&edl->folders);
        }
 
        if( !parent_edl ) {
@@ -472,6 +465,10 @@ int EDL::copy(double start, double end, int all,
        return copy(start, end, all,
                "/EDL", file, output_path, rewind_it);
 }
+int EDL::copy(int all, FileXML *file, const char *output_path, int rewind_it)
+{
+       return copy(0, tracks->total_length(), all, file, output_path, rewind_it);
+}
 
 int EDL::copy_clip(double start, double end, int all,
        FileXML *file, const char *output_path, int rewind_it)
@@ -480,6 +477,11 @@ int EDL::copy_clip(double start, double end, int all,
        return copy(start, end, all,
                "/CLIP_EDL", file, output_path, rewind_it);
 }
+int EDL::copy_clip(int all, FileXML *file, const char *output_path, int rewind_it)
+{
+       return copy_clip(0, tracks->total_length(), all, file, output_path, rewind_it);
+}
+
 int EDL::copy_nested_edl(double start, double end, int all,
        FileXML *file, const char *output_path, int rewind_it)
 {
@@ -488,6 +490,11 @@ int EDL::copy_nested_edl(double start, double end, int all,
        return copy(start, end, all,
                "/NESTED_EDL", file, output_path, rewind_it);
 }
+int EDL::copy_nested_edl(int all, FileXML *file, const char *output_path, int rewind_it)
+{
+       return copy_nested_edl(0, tracks->total_length(), all, file, output_path, rewind_it);
+}
+
 int EDL::copy_vwindow_edl(double start, double end, int all,
        FileXML *file, const char *output_path, int rewind_it)
 {
@@ -495,6 +502,11 @@ int EDL::copy_vwindow_edl(double start, double end, int all,
        return copy(start, end, all,
                "/VWINDOW_EDL", file, output_path, rewind_it);
 }
+int EDL::copy_vwindow_edl(int all, FileXML *file, const char *output_path, int rewind_it)
+{
+       return copy_vwindow_edl(0, tracks->total_length(), all, file, output_path, rewind_it);
+}
+
 
 int EDL::copy(double start, double end, int all,
        const char *closer, FileXML *file,
@@ -527,16 +539,7 @@ int EDL::copy(double start, double end, int all,
                session->save_xml(file);
                session->save_video_config(file);
                session->save_audio_config(file);
-
-// Folders
-               for( int i=0; i<folders.size(); ++i ) {
-                       file->tag.set_title("FOLDER");
-                       file->append_tag();
-                       file->append_text(folders[i]);
-                       file->tag.set_title("/FOLDER");
-                       file->append_tag();
-                       file->append_newline();
-               }
+               folders.save_xml(file);
 
                if( !parent_edl )
                        copy_assets(start, end, file, all, output_path);
@@ -549,12 +552,10 @@ int EDL::copy(double start, double end, int all,
 // Don't want this if using clipboard
                if( all ) {
                        for( int i=0; i<total_vwindow_edls(); ++i )
-                               get_vwindow_edl(i)->copy_vwindow_edl(0, tracks->total_length(), 1,
-                                       file, output_path, 0);
+                               get_vwindow_edl(i)->copy_vwindow_edl(1, file, output_path, 0);
 
                        for( int i=0; i<clips.size(); ++i )
-                               clips[i]->copy_clip(0, tracks->total_length(), 1,
-                                       file, output_path, 0);
+                               clips[i]->copy_clip(1, file, output_path, 0);
 
                        mixers.save(file);
                }
@@ -580,21 +581,49 @@ int EDL::copy(double start, double end, int all,
        return 0;
 }
 
-int EDL::to_nested(EDL *nested_edl)
+void EDL::copy_indexables(EDL *edl)
 {
-// Keep frame rate, sample rate, and output size unchanged.
-// These parameters would revert the project if VWindow displayed an asset
-// of different size than the project.
+       for( Track *track=edl->tracks->first; track; track=track->next ) {
+               for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
+                       if( edit->asset )
+                               assets->update(edit->asset);
+                       if( edit->nested_edl )
+                               nested_edls.get_nested(edit->nested_edl);
+               }
+       }
+}
 
+EDL *EDL::new_nested(EDL *edl, const char *path)
+{
+       EDL *nested = new EDL;  // no parent for nested edl
+       nested->create_objects();
+       nested->copy_session(edl);
+       nested->set_path(path);
+       nested->update_index(edl);
+       nested->copy_indexables(edl);
+       nested->tracks->copy_from(edl->tracks);
+       nested_edls.append(nested);
+       return nested;
+}
+
+EDL *EDL::create_nested_clip(EDL *nested)
+{
+       EDL *new_edl = new EDL(this);  // parent for clip edl
+       new_edl->create_objects();
+       new_edl->create_nested(nested);
+       return new_edl;
+}
+
+void EDL::create_nested(EDL *nested)
+{
+// Keep frame rate, sample rate, and output size unchanged.
 // Nest all video & audio outputs
        session->video_tracks = 1;
-       session->audio_tracks = nested_edl->session->audio_channels;
+       session->audio_tracks = nested->session->audio_channels;
        create_default_tracks();
-       insert_asset(0, nested_edl, 0, 0, 0);
-       return 0;
+       insert_asset(0, nested, 0, 0, 0);
 }
 
-
 void EDL::retrack()
 {
        int min_w = session->output_w, min_h = session->output_h;
@@ -690,6 +719,7 @@ double EDL::equivalent_output(EDL *edl)
 
 void EDL::set_path(const char *path)
 {
+       if( &this->path[0] == path ) return;
        strcpy(this->path, path);
 }
 
@@ -1014,7 +1044,7 @@ void EDL::insert_asset(Asset *asset,
        EDL *new_nested_edl = 0;
 
        if( asset ) new_asset = assets->update(asset);
-       if( nested_edl ) new_nested_edl = nested_edls.get_copy(nested_edl);
+       if( nested_edl ) new_nested_edl = nested_edls.get_nested(nested_edl);
 
 // Paste video
        int vtrack = 0;
@@ -1097,13 +1127,15 @@ void EDL::set_index_file(Indexable *indexable)
 void EDL::optimize()
 {
 //printf("EDL::optimize 1\n");
-       if( local_session->preview_start < 0 ) local_session->preview_start = 0;
        double length = tracks->total_length();
-       if( local_session->preview_end > length ) local_session->preview_end = length;
-       if( local_session->preview_start >= local_session->preview_end  ) {
-               local_session->preview_start = 0;
-               local_session->preview_end = length;
-       }
+       double preview_start = local_session->preview_start;
+       double preview_end = local_session->preview_end;
+       if( preview_end < 0 || preview_end > length )
+               preview_end = length;
+       if( preview_start == 0 && preview_end >= length )
+               local_session->preview_end = -1;
+       if( preview_start > preview_end )
+               local_session->preview_start = preview_end;
        for( Track *current=tracks->first; current; current=NEXT )
                current->optimize();
 }
@@ -1164,18 +1196,58 @@ double EDL::align_to_frame(double position, int round)
 }
 
 
-void EDL::new_folder(const char *folder)
+BinFolder *EDL::get_folder(int no)
+{
+       for( int i=0; i<folders.size(); ++i ) {
+               BinFolder *fp = folders[i];
+               if( no == fp->awindow_folder ) return fp;
+       }
+       return 0;
+}
+
+int EDL::get_folder_number(const char *title)
 {
-       for( int i=0; i<folders.size(); ++i )
-               if( !strcasecmp(folders[i], folder) ) return;
-       folders.append(cstrdup(folder));
+       for( int i=0; i<AWINDOW_FOLDERS; ++i ) {
+               if( !strcmp(title, AWindowGUI::folder_names[i]) )
+                       return i;
+       }
+       for( int i=0; i<folders.size(); ++i ) {
+               if( !strcmp(title, folders[i]->title) )
+                       return folders[i]->awindow_folder;
+       }
+        return AW_NO_FOLDER;
 }
 
-void EDL::delete_folder(const char *folder)
+const char *EDL::get_folder_name(int no)
 {
-       int i = folders.size();
-       while( --i >= 0 && strcasecmp(folders[i], folder) );
-       if( i >= 0 ) folders.remove_number(i);
+       if( no >= 0 && no<AWINDOW_FOLDERS )
+               return AWindowGUI::folder_names[no];
+       BinFolder *fp = get_folder(no);
+       return !fp ? "" : fp->title;
+}
+
+int EDL::new_folder(const char *title, int is_clips)
+{
+       if( !title[0] ) return 1;
+       int ret = get_folder_number(title);
+       if( ret >= 0 ) return 1;
+       int idx = AWINDOW_FOLDERS;
+       for( int i=0; i<folders.size(); ++i ) {
+               BinFolder *fp = folders[i];
+               int no = fp->awindow_folder;
+               if( no >= idx ) idx = no+1;
+       }
+       folders.append(new BinFolder(idx, is_clips, title));
+       return 0;
+}
+
+int EDL::delete_folder(const char *title)
+{
+       int k = folders.size();
+       while( --k >= 0 && strcmp(title, folders[k]->title) );
+       if( k >= 0 )
+               folders.remove_object_number(k);
+       return k;
 }
 
 int EDL::get_use_vconsole(VEdit* *playable_edit,
@@ -1330,7 +1402,6 @@ int64_t EDL::get_video_frames()
                session->frame_rate);
 }
 
-
 void EDL::remove_vwindow_edls()
 {
        for( int i=0; i<total_vwindow_edls(); ++i ) {
@@ -1415,3 +1486,138 @@ double EDL::prev_edit(double position)
        return new_position;
 }
 
+void EDL::rescale_proxy(int orig_scale, int new_scale)
+{
+       if( orig_scale == new_scale ) return;
+// project size
+       float orig_w = (float)session->output_w * orig_scale;
+       float orig_h = (float)session->output_h * orig_scale;
+       if( !parent_edl ) {
+               session->output_w = Units::round(orig_w / new_scale);
+               session->output_h = Units::round(orig_h / new_scale);
+       }
+
+// track sizes
+       for( Track *track=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);
+       }
+}
+
+void EDL::set_proxy(int new_scale, int use_scaler,
+       ArrayList<Indexable*> *orig_assets, ArrayList<Indexable*> *proxy_assets)
+{
+       int orig_scale = session->proxy_scale;
+       int orig_use_scaler = session->proxy_use_scaler;
+
+// rescale to full size asset in read_frame
+       session->proxy_scale = new_scale;
+       session->proxy_use_scaler = use_scaler;
+
+       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 )
+               rescale_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 ) {
+               const char *orig_path = orig_assets->get(i)->path;
+               Indexable *proxy_idxbl = proxy_assets->get(i);
+               proxy_idxbl->awindow_folder = awindow_folder;
+               Asset *proxy_asset = proxy_idxbl->is_asset ? assets->update((Asset *)proxy_idxbl) : 0;
+               EDL *proxy_edl = !proxy_idxbl->is_asset ? (EDL *)proxy_idxbl : 0;
+// replace track contents
+               for( Track *track=tracks->first; track; track=track->next ) {
+                       if( track->data_type != TRACK_VIDEO ) continue;
+                       for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
+                               Indexable *idxbl = (Indexable *)edit->asset;
+                               if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
+                               if( !idxbl ) continue;
+                               if( strcmp(idxbl->path, orig_path) ) continue;
+                               edit->asset = proxy_asset;
+                               edit->nested_edl = proxy_edl;
+                       }
+               }
+               for( int j=0,m=clips.size(); j<m; ++j ) {
+                       EDL *clip = clips[j];
+                       int has_proxy = 0;
+                       for( Track *track=clip->tracks->first; track; track=track->next ) {
+                               if( track->data_type != TRACK_VIDEO ) continue;
+                               for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
+                                       Indexable *idxbl = (Indexable *)edit->asset;
+                                       if( !idxbl ) idxbl = (Indexable *)edit->nested_edl;
+                                       if( !idxbl ) continue;
+                                       if( strcmp(idxbl->path, orig_path) ) continue;
+                                       edit->asset = proxy_asset;
+                                       edit->nested_edl = proxy_edl;
+                                       has_proxy = 1;
+                               }
+                       }
+                       if( has_proxy && !orig_use_scaler )
+                               clip->rescale_proxy(orig_scale, new_scale);
+               }
+       }
+}
+
+void EDL::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 = assets->update((Asset *)proxy_assets->get(i));
+               proxy_asset->awindow_folder = AW_PROXY_FOLDER;
+// replace track contents
+               for( Track *track=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;
+                               }
+                       }
+               }
+       }
+}
+
+Asset *EDL::get_proxy_asset()
+{
+       return awindow_folder == AW_PROXY_FOLDER ?
+               tracks->first->edits->first->asset : 0;
+}
+
+double EDL::get_cursor_position(int cursor_x, int pane_no)
+{
+       return (double)cursor_x * local_session->zoom_sample / session->sample_rate +
+               (double)local_session->view_start[pane_no] *
+                       local_session->zoom_sample / session->sample_rate;
+}
+