switch move/swap tracks, add mv trk shortcut, update msg
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / tracks.C
index 4873fac020d351c396da0fb0914c2d8be64ae38c..07524f1f342ccb296a1b32dfb9eda4b6e6b7071d 100644 (file)
@@ -35,6 +35,7 @@
 #include "panauto.h"
 #include "panautos.h"
 #include "patchbay.h"
+#include "plugin.h"
 #include "mainsession.h"
 #include "strack.h"
 #include "theme.h"
@@ -113,30 +114,28 @@ void Tracks::clear_selected_edits()
        }
 }
 
-void Tracks::select_affected_edits(double position, Track *start_track, int sense)
+void Tracks::get_selected_edits(ArrayList<Edit*> *drag_edits)
 {
-       for( Track *track=start_track; track; track=track->next ) {
-               if( !track->record ) continue;
+       drag_edits->remove_all();
+       for( Track *track=first; track; track=track->next ) {
+               if( !track->is_armed() ) continue;
                for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
-                       if( edit->silence() ) continue;
-                       double startproject = track->from_units(edit->startproject);
-                       if( edl->equivalent(startproject, position) ) {
-                               edit->is_selected = sense >= 0 ? sense :
-                                       edit->is_selected ? 0 : 1;
-                               break;
-                       }
+                       if( !edit->is_selected ) continue;
+                       drag_edits->append(edit);
                }
        }
 }
 
-void Tracks::get_selected_edits(ArrayList<Edit*> *drag_edits)
+void Tracks::select_edits(double start, double end)
 {
-       drag_edits->remove_all();
        for( Track *track=first; track; track=track->next ) {
-               if( !track->record ) continue;
+               if( !track->is_armed() ) continue;
+               int64_t start_pos = track->to_units(start, 0);
+               int64_t end_pos = track->to_units(end, 0);
                for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
-                       if( !edit->is_selected ) continue;
-                       drag_edits->append(edit);
+                       if( start_pos >= edit->startproject+edit->length ) continue;
+                       if( edit->startproject >= end_pos ) continue;
+                       edit->is_selected = 1;
                }
        }
 }
@@ -152,7 +151,7 @@ void Tracks::get_automation_extents(float *min,
        int coords_undefined = 1;
        for(Track *current = first; current; current = NEXT)
        {
-               if(current->record)
+               if(current->is_armed())
                {
                        current->automation->get_extents(min,
                                max,
@@ -170,6 +169,8 @@ void Tracks::copy_from(Tracks *tracks)
        Track *new_track = 0;
 
        delete_all_tracks();
+       int solo_track_id = tracks->edl->local_session->solo_track_id;
+
        for(Track *current = tracks->first; current; current = NEXT)
        {
                switch(current->data_type)
@@ -187,6 +188,9 @@ void Tracks::copy_from(Tracks *tracks)
                        continue;
                }
                new_track->copy_from(current);
+
+               if( current->get_id() == solo_track_id )
+                       edl->local_session->solo_track_id = new_track->get_id();
        }
 }
 
@@ -325,35 +329,48 @@ Track* Tracks::add_subttl_track(int above, Track *dst_track)
 }
 
 
-int Tracks::delete_track(Track *track)
+int Tracks::delete_track(Track *track, int gang)
 {
-       if (!track)
-               return 0;
-
-       int old_location = number_of(track);
-       detach_shared_effects(old_location);
-
+       if( !track ) return 0;
+       if( gang < 0 )
+               gang = edl->session->gang_tracks != GANG_NONE ? 1 : 0;
+       Track *nxt = track->next;
+       if( gang ) {
+               track = track->gang_master();
+               while( nxt && !nxt->master )
+                       nxt = nxt->next;
+       }
+       Track *current = track;
+       int old_location = number_of(current);
+       for( Track *next_track=0; current!=nxt; current=next_track ) {
+               next_track = current->next;
+               detach_shared_effects(old_location);
+               for( Track *curr=current; curr; curr=curr->next ) {
 // Shift effects referencing effects below the deleted track
-       for(Track *current = track;
-               current;
-               current = NEXT)
-       {
-               change_modules(number_of(current), number_of(current) - 1, 0);
+                       change_modules(number_of(curr), number_of(curr)-1, 0);
+               }
+               delete current;
        }
-       if(track) delete track;
-
        return 0;
 }
 
 int Tracks::detach_shared_effects(int module)
 {
-       for(Track *current = first; current; current = NEXT)
-       {
+       for( Track *current=first; current; current=NEXT ) {
                current->detach_shared_effects(module);
        }
-
        return 0;
- }
+} 
+int Tracks::detach_ganged_effects(Plugin *plugin)
+{
+       if( edl->session->gang_tracks == GANG_NONE ) return 1;
+       for( Track *current=first; current; current=NEXT ) {
+               if( current == plugin->track ) continue;
+               if( !current->armed_gang(plugin->track) ) continue;
+               current->detach_ganged_effects(plugin);
+       }
+       return 0;
+}
 
 int Tracks::total_of(int type)
 {
@@ -369,8 +386,8 @@ int Tracks::total_of(int type)
 
                result +=
                        (current->play && type == PLAY) ||
-                       (current->record && type == RECORD) ||
-                       (current->gang && type == GANG) ||
+                       (current->is_armed() && type == RECORD) ||
+                       (current->is_ganged() && type == GANG) ||
                        (current->draw && type == DRAW) ||
                        (mute_auto->value && type == MUTE) ||
                        (current->expand_view && type == EXPAND);
@@ -382,7 +399,7 @@ int Tracks::recordable_audio_tracks()
 {
        int result = 0;
        for(Track *current = first; current; current = NEXT)
-               if(current->data_type == TRACK_AUDIO && current->record) result++;
+               if(current->data_type == TRACK_AUDIO && current->is_armed()) result++;
        return result;
 }
 
@@ -391,7 +408,7 @@ int Tracks::recordable_video_tracks()
        int result = 0;
        for(Track *current = first; current; current = NEXT)
        {
-               if(current->data_type == TRACK_VIDEO && current->record) result++;
+               if(current->data_type == TRACK_VIDEO && current->is_armed()) result++;
        }
        return result;
 }
@@ -461,7 +478,7 @@ double Tracks::total_recordable_length()
        double total = -1;
        for(Track *current = first; current; current = NEXT)
        {
-               if(current->record)
+               if(current->is_armed())
                {
                        double length = current->get_length();
                        if(length > total) total = length;
@@ -517,14 +534,62 @@ double Tracks::total_length_framealigned(double fps)
        return 0;
 }
 
-void Tracks::translate_projector(float offset_x, float offset_y)
+void Tracks::translate_fauto_xy(int fauto, float dx, float dy, int all)
 {
-       for(Track *current = first; current; current = NEXT)
-       {
-               if(current->data_type == TRACK_VIDEO)
-               {
-                       ((VTrack*)current)->translate(offset_x, offset_y, 0);
-               }
+       Track *track = first;
+       for( ; track; track=track->next ) {
+               if( !all && !track->is_armed() ) continue;
+               if( track->data_type != TRACK_VIDEO ) continue;
+               ((VTrack*)track)->translate(fauto, dx, dy, all);
+       }
+}
+
+void Tracks::translate_projector(float dx, float dy, int all)
+{
+       translate_fauto_xy(AUTOMATION_PROJECTOR_X, dx, dy, all);
+}
+
+void Tracks::translate_camera(float dx, float dy, int all)
+{
+       translate_fauto_xy(AUTOMATION_CAMERA_X, dx, dy, all);
+}
+
+void Tracks::crop_resize(float x, float y, float z)
+{
+       float ctr_x = edl->session->output_w / 2.;
+       float ctr_y = edl->session->output_h / 2.;
+       Track *track = first;
+       for( ; track; track=track->next ) {
+               if( !track->is_armed() ) continue;
+               if( track->data_type != TRACK_VIDEO ) continue;
+               float px, py, pz;
+               track->get_projector(px, py, pz);
+               float old_x = px + ctr_x;
+               float old_y = py + ctr_y;
+               float nx = (old_x - x) * z;
+               float ny = (old_y - y) * z;
+               track->set_projector(nx, ny, pz * z);
+       }
+}
+
+void Tracks::crop_shrink(float x, float y, float z)
+{
+       float ctr_x = edl->session->output_w / 2.;
+       float ctr_y = edl->session->output_h / 2.;
+       Track *track = first;
+       for( ; track; track=track->next ) {
+               if( !track->is_armed() ) continue;
+               if( track->data_type != TRACK_VIDEO ) continue;
+               float cx, cy, cz, px, py, pz;
+               track->get_camera(cx, cy, cz);
+               track->get_projector(px, py, pz);
+               float dx = x - (px + ctr_x);
+               float dy = y - (py + ctr_y);
+               cz *= pz;
+               cx += dx / cz;  cy += dy / cz;
+               track->set_camera(cx, cy, cz * z);
+               px += dx;  py += dy;
+               track->set_projector(px, py, 1 / z);
        }
 }
 
@@ -536,6 +601,7 @@ void Tracks::update_y_pixels(Theme *theme)
        {
 //printf("Tracks::update_y_pixels %d\n", y);
                current->y_pixel = y;
+               if( current->is_hidden() ) continue;
                y += current->vertical_span(theme);
        }
 }
@@ -559,8 +625,8 @@ void Tracks::select_all(int type,
                double position = edl->local_session->get_selectionstart(1);
 
                if(type == PLAY) current->play = value;
-               if(type == RECORD) current->record = value;
-               if(type == GANG) current->gang = value;
+               if(type == RECORD) current->armed = value;
+               if(type == GANG) current->ganged = value;
                if(type == DRAW) current->draw = value;
 
                if(type == MUTE)
@@ -599,7 +665,7 @@ int Tracks::totalpixels()
        int result = 0;
        for(Track* current = first; current; current = NEXT)
        {
-               result += edl->local_session->zoom_track;
+               result += current->data_h;
        }
        return result;
 }
@@ -625,6 +691,12 @@ Track* Tracks::number(int number)
        return current;
 }
 
+Track* Tracks::get_track_by_id(int id)
+{
+       Track *track = edl->tracks->first;
+       while( track && track->get_id() != id ) track = track->next;
+       return track;
+}
 
 int Tracks::total_playable_vtracks()
 {
@@ -636,13 +708,14 @@ int Tracks::total_playable_vtracks()
        return result;
 }
 
-int Tracks::plugin_exists(Plugin *plugin)
+Plugin *Tracks::plugin_exists(int plugin_id)
 {
-       for(Track *track = first; track; track = track->next)
-       {
-               if(track->plugin_exists(plugin)) return 1;
+       if( plugin_id < 0 ) return 0;
+       Plugin *plugin = 0;
+       for( Track *track=first; !plugin && track; track=track->next ) {
+               plugin = track->plugin_exists(plugin_id);
        }
-       return 0;
+       return plugin;
 }
 
 int Tracks::track_exists(Track *track)
@@ -658,7 +731,7 @@ int Tracks::new_group(int id)
 {
        int count = 0;
        for( Track *track=first; track; track=track->next ) {
-               if( !track->record ) continue;
+               if( !track->is_armed() ) continue;
                for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
                        if( edit->group_id > 0 ) continue;
                        if( !edit->is_selected ) continue;
@@ -672,10 +745,13 @@ int Tracks::new_group(int id)
 int Tracks::set_group_selected(int id, int v)
 {
        int count = 0;
+       int gang = edl->session->gang_tracks != GANG_NONE ? 1 : 0;
        for( Track *track=first; track; track=track->next ) {
+               if( track->is_hidden() ) continue;
                for( Edit *edit=track->edits->first; edit; edit=edit->next ) {
                        if( edit->group_id != id ) continue;
-                       edit->is_selected = v >= 0 ? v : !edit->is_selected ? 1 : 0;
+                       if( v < 0 ) v = !edit->is_selected ? 1 : 0;
+                       edit->select_affected_edits(v, gang);
                        ++count;
                }
        }
@@ -706,3 +782,57 @@ Track *Tracks::get(int idx, int data_type)
        return 0;
 }
 
+void Tracks::roll_tracks(Track *src, Track *dst, int n)
+{
+       if( src == dst ) return;
+       while( --n >= 0 && src ) {
+               Track *nxt = src->next;
+               change_modules(number_of(src), total(), 0);
+               for( Track *track=nxt; track; track=track->next )
+                       change_modules(number_of(track), number_of(track)-1, 0);
+               remove_pointer(src);
+               int ndst = dst ? number_of(dst) : total();
+               insert_before(dst, src);
+               for( Track *track=last; track && track!=src; track=track->previous ) 
+                       change_modules(number_of(track)-1, number_of(track), 0);
+               change_modules(total(), ndst, 0);
+               src = nxt;
+       }
+}
+
+double Tracks::align_timecodes()
+{
+       double offset = -1;
+       for( Track *track=first; track; track=track->next ) {
+               if( !track->is_armed() ) continue;
+               double early_offset = track->edits->early_timecode();
+               if( offset < 0 || offset > early_offset )
+                       offset = early_offset;
+       }
+       if( offset >= 0 ) {
+               for( Track *track=first; track; track=track->next ) {
+                       if( !track->is_armed() ) continue;
+                       track->edits->align_timecodes(offset);
+               }
+       }
+       return offset;
+}
+
+void Tracks::update_idxbl_length(int id, double dt)
+{
+       for( Track *track=first; track; track=track->next ) {
+               if( !track->is_armed() ) continue;
+               int64_t du = track->to_units(dt,0);
+               track->edits->update_idxbl_length(id, du);
+               track->optimize();
+       }
+}
+
+void Tracks::create_keyframes(double position, int mask, int mode)
+{
+       for( Track *track=first; track; track=track->next ) {
+               if( !track->is_armed() ) continue;
+               track->create_keyframes(position, mask, mode);
+       }
+}
+