improve delays created by vicon drawing locks, reset_cache segv fix, gang track toolt...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / edit.C
index 8ef1735538305bc39f4729e21e76a4fca407f246..f538a503e43de737614bcf25eeb6dc64075e18a4 100644 (file)
@@ -29,6 +29,7 @@
 #include "edlsession.h"
 #include "filexml.h"
 #include "filesystem.h"
+#include "labels.h"
 #include "localsession.h"
 #include "plugin.h"
 #include "mainsession.h"
@@ -51,6 +52,7 @@ Edit::Edit(EDL *edl, Track *track)
        this->track = track;
        if(track) this->edits = track->edits;
        id = EDL::next_id();
+       orig_id = id;
 }
 
 Edit::Edit(EDL *edl, Edits *edits)
@@ -60,6 +62,7 @@ Edit::Edit(EDL *edl, Edits *edits)
        this->edits = edits;
        if(edits) this->track = edits->track;
        id = EDL::next_id();
+       orig_id = id;
 }
 
 Edit::~Edit()
@@ -82,7 +85,6 @@ void Edit::reset()
        channel = 0;
        user_title[0] = 0;
        nested_edl = 0;
-       is_plugin = 0;
        is_selected = 0;
        hard_left = 0;
        hard_right = 0;
@@ -232,8 +234,23 @@ void Edit::insert_transition(char *title)
 
 void Edit::detach_transition()
 {
-       if(transition) delete transition;
+       delete transition;
        transition = 0;
+       if( edl->session->gang_tracks == GANG_NONE ) return;
+       double pos = track->from_units(startproject);
+       Track *current = edl->tracks->first;
+       for( ; current; current=current->next ) {
+               if( current == track ) continue;
+               if( current->data_type != track->data_type ) continue;
+               if( !current->armed_gang(track) ) continue;
+               int64_t track_pos = current->to_units(pos, 1);
+               Edit *edit = current->edits->editof(track_pos, PLAY_FORWARD, 0);
+               if( !edit ) continue;
+               double edit_pos = track->from_units(edit->startproject);
+               if( !edl->equivalent(pos, edit_pos) ) continue;
+               delete edit->transition;
+               edit->transition = 0;
+       }
 }
 
 int Edit::silence()
@@ -242,18 +259,42 @@ int Edit::silence()
                asset || nested_edl :
                *((SEdit *)this)->get_text()) ? 0 : 1;
 }
-void Edit::mute()
+
+void Edit::set_selected(int v)
 {
-       if( track->data_type != TRACK_SUBTITLE ) {
-               asset = 0;
-               nested_edl = 0;
+       if( !group_id ) {
+               if( v < 0 ) v = !is_selected ? 1 : 0;
+               int gang = edl->session->gang_tracks != GANG_NONE ? 1 : 0;
+               select_affected_edits(v, gang);
        }
        else
-               *((SEdit *)this)->get_text() = 0;
+               edl->tracks->set_group_selected(group_id, v);
+}
+
+// gang<0: rest of tracks, gang==0: this track, gang>0: to next master
+void Edit::select_affected_edits(int v, int gang)
+{
+       is_selected = v;
+       if( !gang ) return;
+       double position = track->from_units(startproject);
+       for( Track *current=track->next; current; current=current->next ) {
+               if( gang > 0 && current->master ) break;
+               if( !current->is_armed() ) continue;
+               for( Edit *edit=current->edits->first; edit; edit=edit->next ) {
+                       if( edit->silence() ) continue;
+                       double start = current->from_units(edit->startproject);
+                       if( edl->equivalent(start, position) ) {
+                               edit->is_selected = v;
+                               break;
+                       }
+               }
+       }
 }
 
+
 void Edit::copy_from(Edit *edit)
 {
+       this->orig_id = edit->orig_id;
        this->nested_edl = edl->nested_edls.get_nested(edit->nested_edl);
        this->asset = edl->assets->update(edit->asset);
        this->startsource = edit->startsource;
@@ -276,6 +317,12 @@ void Edit::copy_from(Edit *edit)
        this->channel = edit->channel;
 }
 
+void Edit::clone_from(Edit *edit)
+{
+       copy_from(edit);
+       edit->orig_id = edit->id;
+}
+
 void Edit::equivalent_output(Edit *edit, int64_t *result)
 {
 // End of edit changed
@@ -371,33 +418,32 @@ double Edit::picon_w()
                w = nested_edl->session->output_w;
                h = nested_edl->session->output_h;
        }
-       return w>0 && h>0 ? ((double)edl->local_session->zoom_track*w)/h : 0;
+       return w>0 && h>0 ? ((double)track->data_h*w)/h : 0;
 }
 
 int Edit::picon_h()
 {
-       return edl->local_session->zoom_track;
+       return track->data_h;
 }
 
 
 int Edit::dump(FILE *fp)
 {
        fprintf(fp,"     EDIT %p\n", this); fflush(fp);
-       fprintf(fp,"      nested_edl=%p %s asset=%p %s\n",
-               nested_edl,
-               nested_edl ? nested_edl->path : "",
-               asset,
-               asset ? asset->path : "");
+       fprintf(fp,"      id %d, orig_id %d, nested_edl=%p %s asset=%p %s\n",
+               id, orig_id, nested_edl, nested_edl ? nested_edl->path : "",
+               asset, asset ? asset->path : "");
        fflush(fp);
-       fprintf(fp,"      channel %d, color %08x, group_id %d, is_selected %d\n",
-               channel, color, group_id, is_selected);
-       if(transition)
-       {
+       fprintf(fp,"      channel %d, color %08x, hard lt/rt %d/%d"
+               " group_id %d, is_selected %d\n",
+               channel, color, hard_left, hard_right, group_id, is_selected);
+       if( transition ) {
                fprintf(fp,"      TRANSITION %p\n", transition);
                transition->dump(fp);
        }
-       fprintf(fp,"      startsource %jd startproject %jd hard lt/rt %d/%d length %jd\n",
-               startsource, startproject, hard_left, hard_right, length); fflush(fp);
+       fprintf(fp,"      startsource %jd startproject %jd length %jd\n",
+               startsource, startproject, length);
+       fflush(fp);
        return 0;
 }
 
@@ -418,353 +464,220 @@ int Edit::load_properties(FileXML *file, int64_t &startproject)
 
 void Edit::shift(int64_t difference)
 {
-//printf("Edit::shift 1 %p %jd %jd\n", this, startproject, difference);
        startproject += difference;
-//printf("Edit::shift 2 %jd %jd\n", startproject, difference);
 }
 
-int Edit::shift_start_in(int edit_mode,
-       int64_t newposition,
-       int64_t oldposition,
-       int edit_edits,
-       int edit_labels,
-       int edit_plugins,
-       int edit_autos,
-       Edits *trim_edits)
+void Edit::trim(int64_t difference)
 {
-       int64_t cut_length = newposition - oldposition;
-       int64_t end_previous_source, end_source;
-
-       if(edit_mode == MOVE_ALL_EDITS)
-       {
-               if(cut_length < length)
-               {        // clear partial
-                       edits->clear_recursive(oldposition,
-                               newposition,
-                               edit_edits,
-                               edit_labels,
-                               edit_plugins,
-                               edit_autos,
-                               trim_edits);
-               }
-               else
-               {        // clear entire
-                       edits->clear_recursive(oldposition,
-                               startproject + length,
-                               edit_edits,
-                               edit_labels,
-                               edit_plugins,
-                               edit_autos,
-                               trim_edits);
-               }
+       length += difference;
+       if( startproject < 0 ) {
+               if( (startsource+=startproject) < 0 ) startsource = 0;
+               if( (length+=startproject) < 0 ) length = 0;
+               startproject = 0;
        }
-       else
-       if(edit_mode == MOVE_ONE_EDIT)
-       {
-// Paste silence and cut
-//printf("Edit::shift_start_in 1\n");
-               if(!previous)
-               {
-                       Edit *new_edit = edits->create_edit();
-                       new_edit->startproject = this->startproject;
-                       new_edit->length = 0;
-                       edits->insert_before(this,
-                               new_edit);
-               }
-//printf("Edit::shift_start_in 2 %p\n", previous);
-
-               end_previous_source = previous->get_source_end(previous->startsource + previous->length + cut_length);
-               if(end_previous_source > 0 &&
-                       previous->startsource + previous->length + cut_length > end_previous_source)
-                       cut_length = end_previous_source - previous->startsource - previous->length;
-
-               if(cut_length < length)
-               {               // Move in partial
-                       startproject += cut_length;
-                       startsource += cut_length;
-                       length -= cut_length;
-                       previous->length += cut_length;
-//printf("Edit::shift_start_in 2\n");
-               }
-               else
-               {               // Clear entire edit
-                       cut_length = length;
-                       previous->length += cut_length;
-                       for(Edit* current_edit = this; current_edit; current_edit = current_edit->next)
-                       {
-                               current_edit->startproject += cut_length;
-                       }
-                       edits->clear_recursive(oldposition + cut_length,
-                               startproject + cut_length,
-                               edit_edits,
-                               edit_labels,
-                               edit_plugins,
-                               edit_autos,
-                               trim_edits);
-               }
-//printf("Edit::shift_start_in 3\n");
+       if( startsource < 0 )
+               startsource = 0;
+       int64_t src_len = get_source_end(INT64_MAX);
+       if( startsource + length > src_len ) {
+               length = src_len - startsource;
+               if( length < 0 ) length = 0;
        }
-       else
-       if(edit_mode == MOVE_NO_EDITS)
-       {
-               end_source = get_source_end(startsource + length + cut_length);
-               if(end_source > 0 && startsource + length + cut_length > end_source)
-                       cut_length = end_source - startsource - length;
-
-               startsource += cut_length;
-       }
-       return 0;
+       if( length < 0 )
+               length = 0;
 }
 
-int Edit::shift_start_out(int edit_mode,
-       int64_t newposition,
-       int64_t oldposition,
-       int edit_edits,
-       int edit_labels,
-       int edit_plugins,
-       int edit_autos,
-       Edits *trim_edits)
+int Edit::shift_start(int edit_mode, int64_t newposition, int64_t oldposition,
+       int edit_labels, int edit_autos, int edit_plugins, Edits *trim_edits)
 {
-       int64_t cut_length = oldposition - newposition;
-
-
-       if(asset || nested_edl)
-       {
-               int64_t end_source = get_source_end(1);
-
-//printf("Edit::shift_start_out 1 %jd %jd\n", startsource, cut_length);
-               if(end_source > 0 && startsource < cut_length)
-               {
-                       cut_length = startsource;
+       int64_t cut_length = newposition - oldposition;
+       int rest_moved = edit_mode == MOVE_RIPPLE || edit_mode == MOVE_EDGE ? 1 : 0;
+       if( cut_length > length )
+               cut_length = length;
+       else if( cut_length < -length )
+               cut_length = -length;
+
+       int64_t start = startproject, end = start + length;
+       Edit *prev = this->previous, *next = this->next;
+       int edits_moved = 0;
+
+       switch( edit_mode ) {
+       case MOVE_RIPPLE:
+               edits_moved = 1;
+               startsource += cut_length;
+               cut_length = -cut_length;
+               length += cut_length;
+               for( Edit *edit=next; edit; edit=edit->next )
+                       edit->startproject += cut_length;
+               break;
+       case MOVE_ROLL:
+               if( prev && prev->length + cut_length < 0 )
+                       cut_length = -prev->length;
+               if( prev ) prev->trim(cut_length);
+               startproject += cut_length;
+               startsource += cut_length;
+               length -= cut_length;
+               break;
+       case MOVE_SLIP:
+               edits_moved = 1;
+               startsource -= cut_length;
+               break;
+       case MOVE_SLIDE:
+               edits_moved = 1;
+               if( prev && prev->length + cut_length < 0 )
+                       cut_length = -prev->length;
+               if( next && next->length - cut_length < 0 )
+                       cut_length = next->length;
+               if( prev ) prev->trim(cut_length);
+               startproject += cut_length;
+               if( next ) {
+                       next->startproject += cut_length;
+                       next->startsource += cut_length;
+                       next->trim(-cut_length);
                }
-       }
-
-       if(edit_mode == MOVE_ALL_EDITS)
-       {
-//printf("Edit::shift_start_out 10 %jd\n", cut_length);
+               break;
+       case MOVE_EDGE:
+               edits_moved = 1;
                startsource -= cut_length;
                length += cut_length;
+               for( Edit *edit=next; edit; edit=edit->next )
+                       edit->startproject += cut_length;
+               break;
+       }
+       trim(0);
+       return follow_edits(start, end, cut_length, edits_moved, rest_moved,
+               edit_labels, edit_autos, edit_plugins, trim_edits);
+}
 
-               if(edit_autos)
-                       edits->shift_keyframes_recursive(startproject,
-                               cut_length);
-               if(edit_plugins)
-                       edits->shift_effects_recursive(startproject,
-                               cut_length,
-                               edit_autos);
-
-               for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
-               {
-                       current_edit->startproject += cut_length;
-               }
+int Edit::shift_end(int edit_mode, int64_t newposition, int64_t oldposition,
+       int edit_labels, int edit_autos, int edit_plugins, Edits *trim_edits)
+{
+       int64_t cut_length = newposition - oldposition;
+       int rest_moved = edit_mode == MOVE_RIPPLE || edit_mode == MOVE_EDGE ? 1 : 0;
+       if( cut_length > length ) {
+                if( !rest_moved ) cut_length = length;
        }
-       else
-       if(edit_mode == MOVE_ONE_EDIT)
-       {
-               if(previous)
-               {
-                       if(cut_length < previous->length)
-                       {   // Cut into previous edit
-                               previous->length -= cut_length;
-                               startproject -= cut_length;
-                               startsource -= cut_length;
-                               length += cut_length;
-                       }
-                       else
-                       {   // Clear entire previous edit
-                               cut_length = previous->length;
-                               previous->length = 0;
-                               length += cut_length;
-                               startsource -= cut_length;
-                               startproject -= cut_length;
-                       }
+       else if( cut_length < -length )
+               cut_length = -length;
+       int64_t start = startproject, end = start + length;
+       Edit *prev = this->previous, *next = this->next;
+       int edits_moved = 0;
+
+       switch( edit_mode ) {
+       case MOVE_RIPPLE:
+       case MOVE_EDGE:
+               length += cut_length;
+               for( Edit *edit=next; edit; edit=edit->next )
+                       edit->startproject += cut_length;
+               break;
+       case MOVE_ROLL:
+               if( next && next->length - cut_length < 0 )
+                       cut_length = next->length;
+               length += cut_length;
+               if( next ) {
+                       next->startproject += cut_length;
+                       next->startsource += cut_length;
+                       next->trim(-cut_length);
                }
-       }
-       else
-       if(edit_mode == MOVE_NO_EDITS)
-       {
+               break;
+       case MOVE_SLIP:
+               edits_moved = 1;
                startsource -= cut_length;
+               break;
+       case MOVE_SLIDE:
+               edits_moved = 1;
+               if( prev && prev->length + cut_length < 0 )
+                       cut_length = -prev->length;
+               if( next && next->length - cut_length < 0 )
+                       cut_length = next->length;
+               if( prev ) prev->trim(cut_length);
+               startproject += cut_length;
+               if( next ) {
+                       next->startproject += cut_length;
+                       next->startsource += cut_length;
+                       next->trim(-cut_length);
+               }
+               break;
        }
-
-// Fix infinite length files
-       if(startsource < 0) startsource = 0;
-       return 0;
-}
-
-int Edit::shift_end_in(int edit_mode,
-       int64_t newposition,
-       int64_t oldposition,
-       int edit_edits,
-       int edit_labels,
-       int edit_plugins,
-       int edit_autos,
-       Edits *trim_edits)
-{
-       int64_t cut_length = oldposition - newposition;
-
-       if(edit_mode == MOVE_ALL_EDITS)
-       {
-//printf("Edit::shift_end_in 1\n");
-               if(newposition > startproject)
-               {        // clear partial edit
-//printf("Edit::shift_end_in %p %p\n", track->edits, edits);
-                       edits->clear_recursive(newposition,
-                               oldposition,
-                               edit_edits,
-                               edit_labels,
-                               edit_plugins,
-                               edit_autos,
-                               trim_edits);
+       trim(0);
+       return follow_edits(start, end, cut_length, edits_moved, rest_moved,
+               edit_labels, edit_autos, edit_plugins, trim_edits);
+}
+
+int Edit::follow_edits(int64_t start, int64_t end, int64_t cut_length,
+               int edits_moved, int rest_moved, int edit_labels, int edit_autos,
+               int edit_plugins, Edits *trim_edits)
+{
+       if( edits_moved && rest_moved ) {
+               if( edit_labels ) {
+                       double cut_len = track->from_units(cut_length);
+                       double start_pos = edits->track->from_units(start);
+                       if( cut_len < 0 )
+                               edits->edl->labels->clear(start_pos + cut_len, start_pos, 1);
+                       else if( cut_len > 0 )
+                               edits->edl->labels->insert(start_pos, cut_len);
                }
-               else
-               {        // clear entire edit
-                       edits->clear_recursive(startproject,
-                               oldposition,
-                               edit_edits,
-                               edit_labels,
-                               edit_plugins,
-                               edit_autos,
-                               trim_edits);
+               if( cut_length < 0 )
+                       track->clear(start + cut_length, start,
+                               0, 0, edit_autos, edit_plugins, trim_edits);
+               else if( cut_length > 0 ) {
+                       if( edit_autos )
+                               track->shift_keyframes(start, cut_length);
+                       if( edit_plugins )
+                               track->shift_effects(start, cut_length, 1, trim_edits);
                }
        }
-       else
-       if(edit_mode == MOVE_ONE_EDIT)
-       {
-               if(next)
-               {
-                       if(next->asset)
-                       {
-                               int64_t end_source = next->get_source_end(1);
-
-                               if(end_source > 0 && next->startsource - cut_length < 0)
-                               {
-                                       cut_length = next->startsource;
-                               }
-                       }
-
-                       if(cut_length < length)
-                       {
-                               length -= cut_length;
-                               next->startproject -= cut_length;
-                               next->startsource -= cut_length;
-                               next->length += cut_length;
-//printf("Edit::shift_end_in 2 %d\n", cut_length);
+       else if( edits_moved ) {
+               if( edit_labels ) {
+                       double cut_len = track->from_units(cut_length);
+                       double start_pos = edits->track->from_units(start);
+                       edits->edl->labels->insert(start_pos, cut_len);
+                       double end_pos = edits->track->from_units(end);
+                       edits->edl->labels->insert(end_pos + cut_len, -cut_len);
+               }
+               if( edit_autos ) {
+                       if( cut_length > 0 ) {
+                               track->clear(end, end+cut_length, 0, 0, 0, 1, 0);
+                               track->shift_keyframes(start, cut_length);
                        }
-                       else
-                       {
-                               cut_length = length;
-                               next->length += cut_length;
-                               next->startsource -= cut_length;
-                               next->startproject -= cut_length;
-                               length -= cut_length;
+                       else if( cut_length < 0 ) {
+                               track->clear(start+cut_length, start, 0, 0, 0, 1, 0);
+                               track->shift_keyframes(end+cut_length, -cut_length);
                        }
                }
-               else
-               {
-                       if(cut_length < length)
-                       {
-                               length -= cut_length;
+               if( edit_plugins ) {
+                       if( cut_length > 0 ) {
+                               track->clear(end, end+cut_length, 0, 0, -1, 0, 0);
+                               track->shift_effects(start, cut_length, 1, 0);
                        }
-                       else
-                       {
-                               cut_length = length;
-                               edits->clear_recursive(startproject,
-                                       oldposition,
-                                       edit_edits,
-                                       edit_labels,
-                                       edit_plugins,
-                                       edit_autos,
-                                       trim_edits);
+                       else if( cut_length < 0 ) {
+                               track->clear(start+cut_length, start, 0, 0, -1, 0, 0);
+                               track->shift_effects(end+cut_length, -cut_length, 1, 0);
                        }
                }
        }
-       else
-// Does nothing for plugins
-       if(edit_mode == MOVE_NO_EDITS)
-       {
-//printf("Edit::shift_end_in 3\n");
-               int64_t end_source = get_source_end(1);
-               if(end_source > 0 && startsource < cut_length)
-               {
-                       cut_length = startsource;
+       else if( rest_moved ) {
+               if( edit_labels ) {
+                       double cut_len = track->from_units(cut_length);
+                       double end_pos = edits->track->from_units(end);
+                       if( cut_len < 0 )
+                               edits->edl->labels->clear(end_pos + cut_len, end_pos, 1);
+                       else if( cut_len > 0 )
+                               edits->edl->labels->insert(end_pos, cut_len);
+               }
+               if( cut_length < 0 )
+                       track->clear(end + cut_length, end,
+                               0, 0, edit_autos, edit_plugins, trim_edits);
+               else if( cut_length > 0 ) {
+                       if( edit_autos )
+                               track->shift_keyframes(end, cut_length);
+                       if( edit_plugins )
+                               track->shift_effects(end, cut_length, 1, trim_edits);
                }
-               startsource -= cut_length;
        }
        return 0;
 }
 
-int Edit::shift_end_out(int edit_mode,
-       int64_t newposition,
-       int64_t oldposition,
-       int edit_edits,
-       int edit_labels,
-       int edit_plugins,
-       int edit_autos,
-       Edits *trim_edits)
-{
-       int64_t cut_length = newposition - oldposition;
-       int64_t endsource = get_source_end(startsource + length + cut_length);
-
-// check end of edit against end of source file
-       if(endsource > 0 && startsource + length + cut_length > endsource)
-               cut_length = endsource - startsource - length;
 
-//printf("Edit::shift_end_out 1 %jd %d %d %d\n", oldposition, newposition, this->length, cut_length);
-       if(edit_mode == MOVE_ALL_EDITS)
-       {
-// Extend length
-               this->length += cut_length;
-
-// Effects are shifted in length extension
-               if(edit_plugins)
-                       edits->shift_effects_recursive(oldposition /* startproject */,
-                               cut_length,
-                               edit_autos);
-               if(edit_autos)
-                       edits->shift_keyframes_recursive(oldposition /* startproject */,
-                               cut_length);
-
-               for(Edit* current_edit = next; current_edit; current_edit = current_edit->next)
-               {
-                       current_edit->startproject += cut_length;
-               }
-       }
-       else
-       if(edit_mode == MOVE_ONE_EDIT)
-       {
-               if(next)
-               {
-                       if(cut_length < next->length)
-                       {
-                               length += cut_length;
-                               next->startproject += cut_length;
-                               next->startsource += cut_length;
-                               next->length -= cut_length;
-//printf("Edit::shift_end_out %d cut_length=%d\n", __LINE__, cut_length);
-                       }
-                       else
-                       {
-//printf("Edit::shift_end_out %d cut_length=%d next->length=%d\n", __LINE__, cut_length, next->length);
-                               cut_length = next->length;
-                               next->startproject += next->length;
-                               next->startsource += next->length;
-                               next->length = 0;
-                               length += cut_length;
-//track->dump();
-                       }
-               }
-               else
-               {
-                       length += cut_length;
-               }
-       }
-       else
-       if(edit_mode == MOVE_NO_EDITS)
-       {
-               startsource += cut_length;
-       }
-       return 0;
-}
 
 int Edit::popup_transition(float view_start, float zoom_units, int cursor_x, int cursor_y)
 {
@@ -787,7 +700,7 @@ int Edit::select_handle(float view_start, float zoom_units, int cursor_x, int cu
 
        int64_t pixel1, pixel2;
        pixel1 = left;
-       pixel2 = pixel1 + 10;
+       pixel2 = pixel1 + xS(10);
 
 // test left edit
 // cursor_x is faked in acanvas
@@ -799,7 +712,7 @@ int Edit::select_handle(float view_start, float zoom_units, int cursor_x, int cu
 
        //int64_t endproject = startproject + length;
        pixel2 = right;
-       pixel1 = pixel2 - 10;
+       pixel1 = pixel2 - xS(10);
 
 // test right edit
        if(cursor_x >= pixel1 && cursor_x <= pixel2)