diff --git a/panels/project.cpp b/panels/project.cpp index e13982ba4..f78203aae 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -265,6 +265,7 @@ void Project::load_project() { int temp_media_id; Sequence* temp_seq; Clip* temp_clip; + int temp_clip_id; int state = LOAD_STATE_IDLE; while (!stream.atEnd()) { @@ -305,13 +306,24 @@ void Project::load_project() { break; case LOAD_STATE_SEQUENCE: if (stream.isEndElement() && stream.name() == "sequence") { - // convert link ids to pointers + // correct IDs for (int i=0;iclip_count();i++) { - Clip* c = temp_seq->get_clip(i); - for (int j=0;jlink_ids.size();j++) { - c->linked.append(temp_seq->get_clip(c->link_ids.at(j))); + Clip* clip = temp_seq->get_clip(i); + + // correct IDs in linked clips + for (int j=0;jlinked.size();j++) { + for (int k=0;kclip_count();k++) { + if (temp_seq->get_clip(k)->id == clip->linked.at(j)) { + clip->linked[j] = k; + break; + } + } } } + for (int i=0;iclip_count();i++) { + // correct actual IDs + temp_seq->get_clip(i)->id = i; + } new_sequence(temp_seq); state = LOAD_STATE_IDLE; @@ -344,11 +356,15 @@ void Project::load_project() { case LOAD_STATE_CLIP: if (stream.isEndElement() && stream.name() == "clip") { temp_seq->add_clip(temp_clip); + temp_clip->id = temp_clip_id; // uses loaded ID (corrects later) state = LOAD_STATE_SEQUENCE; } else if (stream.isStartElement()) { if (stream.name() == "name") { stream.readNext(); temp_clip->name = stream.text().toString(); + } else if (stream.name() == "id") { + stream.readNext(); + temp_clip_id = stream.text().toInt(); } else if (stream.name() == "clipin") { stream.readNext(); temp_clip->clip_in = stream.text().toInt(); @@ -411,7 +427,7 @@ void Project::load_project() { state = LOAD_STATE_CLIP; } else if (stream.isStartElement() && stream.name() == "link") { stream.readNext(); - temp_clip->link_ids.append(stream.text().toInt()); + temp_clip->linked.append(stream.text().toInt()); } break; } @@ -469,42 +485,39 @@ void Project::save_project() { stream.writeTextElement("alayout", QString::number(s->audio_layout)); stream.writeStartElement("clips"); - // give clips IDs for links - for (int i=0;iclip_count();i++) { - s->get_clip(i)->save_id = i; - } - for (int i=0;iclip_count();i++) { Clip* c = s->get_clip(i); - - stream.writeStartElement("clip"); - stream.writeTextElement("name", c->name); - stream.writeTextElement("clipin", QString::number(c->clip_in)); - stream.writeTextElement("in", QString::number(c->timeline_in)); - stream.writeTextElement("out", QString::number(c->timeline_out)); - stream.writeTextElement("track", QString::number(c->track)); - stream.writeStartElement("color"); - stream.writeAttribute("r", QString::number(c->color_r)); - stream.writeAttribute("g", QString::number(c->color_g)); - stream.writeAttribute("b", QString::number(c->color_b)); - stream.writeEndElement(); - stream.writeTextElement("media", QString::number(c->media->save_id)); - stream.writeTextElement("stream", QString::number(c->media_stream->file_index)); - stream.writeStartElement("linked"); - for (int j=0;jlinked.size();j++) { - stream.writeTextElement("link", QString::number(c->linked.at(j)->save_id)); - } - stream.writeEndElement(); - stream.writeStartElement("effects"); - for (int j=0;jeffects.size();j++) { - stream.writeStartElement("effect"); - Effect* e = c->effects.at(j); - stream.writeAttribute("id", QString::number(e->id)); - e->save(&stream); + if (c != NULL) { + stream.writeStartElement("clip"); + stream.writeTextElement("id", QString::number(c->id)); + stream.writeTextElement("name", c->name); + stream.writeTextElement("clipin", QString::number(c->clip_in)); + stream.writeTextElement("in", QString::number(c->timeline_in)); + stream.writeTextElement("out", QString::number(c->timeline_out)); + stream.writeTextElement("track", QString::number(c->track)); + stream.writeStartElement("color"); + stream.writeAttribute("r", QString::number(c->color_r)); + stream.writeAttribute("g", QString::number(c->color_g)); + stream.writeAttribute("b", QString::number(c->color_b)); + stream.writeEndElement(); + stream.writeTextElement("media", QString::number(c->media->save_id)); + stream.writeTextElement("stream", QString::number(c->media_stream->file_index)); + stream.writeStartElement("linked"); + for (int j=0;jlinked.size();j++) { + stream.writeTextElement("link", QString::number(c->linked.at(j))); + } + stream.writeEndElement(); + stream.writeStartElement("effects"); + for (int j=0;jeffects.size();j++) { + stream.writeStartElement("effect"); + Effect* e = c->effects.at(j); + stream.writeAttribute("id", QString::number(e->id)); + e->save(&stream); + stream.writeEndElement(); + } + stream.writeEndElement(); stream.writeEndElement(); } - stream.writeEndElement(); - stream.writeEndElement(); } stream.writeEndElement(); } diff --git a/panels/timeline.cpp b/panels/timeline.cpp index 5af69452f..290602658 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -86,12 +86,14 @@ void Timeline::next_cut() { long n_cut = LONG_MAX; for (int i=0;iclip_count();i++) { Clip* c = sequence->get_clip(i); - if (c->timeline_in < n_cut && c->timeline_in > playhead) { - n_cut = c->timeline_in; - seek_enabled = true; - } else if (c->timeline_out < n_cut && c->timeline_out > playhead) { - n_cut = c->timeline_out; - seek_enabled = true; + if (c != NULL) { + if (c->timeline_in < n_cut && c->timeline_in > playhead) { + n_cut = c->timeline_in; + seek_enabled = true; + } else if (c->timeline_out < n_cut && c->timeline_out > playhead) { + n_cut = c->timeline_out; + seek_enabled = true; + } } } if (seek_enabled) seek(n_cut); @@ -101,9 +103,11 @@ void Timeline::reset_all_audio() { // reset all clip audio for (int i=0;iclip_count();i++) { Clip* c = sequence->get_clip(i); - c->reset_audio = true; - c->frame_sample_index = 0; - c->audio_buffer_write = 0; + if (c != NULL) { + c->reset_audio = true; + c->frame_sample_index = 0; + c->audio_buffer_write = 0; + } } clear_audio_ibuffer(); } @@ -267,7 +271,7 @@ void Timeline::select_all() { selections.clear(); for (int i=0;iclip_count();i++) { Clip* c = sequence->get_clip(i); - selections.append({c->timeline_in, c->timeline_out, c->track}); + if (c != NULL) selections.append({c->timeline_in, c->timeline_out, c->track}); } repaint_timeline(); } @@ -295,10 +299,10 @@ void Timeline::delete_selection(bool ripple_delete) { // check every clip after and see if it'll collide // NOTE, we could probably re-use the validation code for the ripple tool here for optimization (since it's technically better code I think) Clip* c = sequence->get_clip(i); - if (c->timeline_in >= ripple_point) { + if (c != NULL && c->timeline_in >= ripple_point) { for (int j=0;jclip_count();j++) { Clip* cc = sequence->get_clip(j); - if (cc->timeline_in < ripple_point) { + if (cc != NULL && cc->timeline_in < ripple_point) { validator = c->timeline_in - ripple_length - cc->timeline_out; if (validator < 0) ripple_length += validator; @@ -340,7 +344,7 @@ void Timeline::set_zoom(bool in) { void Timeline::ripple(long ripple_point, long ripple_length) { for (int i=0;iclip_count();i++) { Clip* c = sequence->get_clip(i); - if (c->timeline_in >= ripple_point) { + if (c != NULL && c->timeline_in >= ripple_point) { c->timeline_in += ripple_length; c->timeline_out += ripple_length; } @@ -451,7 +455,7 @@ void Timeline::split_clip_and_relink(Clip* pre_clip, long frame, bool relink) { // find linked clips of old clip for (int i=0;ilinked.size();i++) { - Clip* link = pre_clip->linked.at(i); + Clip* link = sequence->get_clip(pre_clip->linked.at(i)); if (!panel_timeline->is_clip_selected(link)) { Clip* s = sequence->split_clip(link, frame); if (s != NULL) splits.append(s); @@ -464,7 +468,7 @@ void Timeline::split_clip_and_relink(Clip* pre_clip, long frame, bool relink) { for (int j=0;jlinked.append(cc); + c->linked.append(cc->id); } } } @@ -479,7 +483,7 @@ void Timeline::delete_areas_and_relink(QVector& areas) { const Selection& s = areas.at(i); for (int j=0;jclip_count();j++) { Clip* c = sequence->get_clip(j); - if (c->track == s.track && !c->undeletable) { + if (c != NULL && c->track == s.track && !c->undeletable) { if (c->timeline_in >= s.in && c->timeline_out <= s.out) { // clips falls entirely within deletion area sequence->delete_clip(j); @@ -513,8 +517,8 @@ void Timeline::delete_areas_and_relink(QVector& areas) { Clip* c = pre_clips.at(i); for (int j=0;jlinked.size();k++) { - if (c->linked.at(k) == pre_clips.at(j)) { - post_clips.at(i)->linked.append(post_clips.at(j)); + if (c->linked.at(k) == pre_clips.at(j)->id) { + post_clips.at(i)->linked.append(post_clips.at(j)->id); } } } @@ -529,33 +533,38 @@ void Timeline::copy(bool del) { for (int i=0;iclip_count();i++) { Clip* c = sequence->get_clip(i); - for (int j=0;jtrack && !((c->timeline_in < s.in && c->timeline_out < s.in) || (c->timeline_in > s.out && c->timeline_out > s.out))) { - if (!cleared) { - clip_clipboard.clear(); - cleared = true; + if (c != NULL) { + for (int j=0;jtrack && !((c->timeline_in < s.in && c->timeline_out < s.in) || (c->timeline_in > s.out && c->timeline_out > s.out))) { + if (!cleared) { + clip_clipboard.clear(); + cleared = true; + } + + Clip* copied_clip = c->copy(); + + // copy linked IDs (we correct these later in paste()) + copied_clip->linked = c->linked; + + if (copied_clip->timeline_in < s.in) { + copied_clip->clip_in += (s.in - copied_clip->timeline_in); + copied_clip->timeline_in = s.in; + } + + if (copied_clip->timeline_out > s.out) { + copied_clip->timeline_out = s.out; + } + + if (copied) { + min_in = qMin(min_in, s.in); + } else { + min_in = s.in; + copied = true; + } + + clip_clipboard.append(copied_clip); } - - Clip* copied_clip = c->copy(); - - if (copied_clip->timeline_in < s.in) { - copied_clip->clip_in += (s.in - copied_clip->timeline_in); - copied_clip->timeline_in = s.in; - } - - if (copied_clip->timeline_out > s.out) { - copied_clip->timeline_out = s.out; - } - - if (copied) { - min_in = qMin(min_in, s.in); - } else { - min_in = s.in; - copied = true; - } - - clip_clipboard.append(copied_clip); } } } @@ -571,6 +580,23 @@ void Timeline::copy(bool del) { } } +void Timeline::relink_clips_using_ids(QVector& old_clips, QVector& new_clips) { + // relink pasted clips + for (int i=0;ilinked.size();j++) { + for (int k=0;kid == oc->linked.at(j)) { + nc->linked.append(new_clips.at(k)->id); + } + } + } + } +} + void Timeline::paste() { if (clip_clipboard.size() > 0) { QVector delete_areas; @@ -579,14 +605,20 @@ void Timeline::paste() { delete_areas.append({c->timeline_in + playhead, c->timeline_out + playhead, c->track}); } delete_areas_and_relink(delete_areas); + + QVector added_clips; for (int i=0;icopy(); cc->timeline_in += playhead; cc->timeline_out += playhead; cc->sequence = sequence; + added_clips.append(cc); sequence->add_clip(cc); } + + relink_clips_using_ids(clip_clipboard, added_clips); + redraw_all_clips(true); } } @@ -600,23 +632,25 @@ bool Timeline::split_selection() { // find clips within selection and split for (int j=0;jclip_count();j++) { - for (int i=0;iget_clip(j); - if (s.track == clip->track) { - Clip* post_a = sequence->split_clip(clip, s.in); - Clip* post_b = sequence->split_clip(clip, s.out); + Clip* clip = sequence->get_clip(j); + if (clip != NULL) { + for (int i=0;itrack) { + Clip* post_a = sequence->split_clip(clip, s.in); + Clip* post_b = sequence->split_clip(clip, s.out); - if (post_a != NULL) { - pre_splits.append(clip); - post_splits.append(post_a); - } - if (post_b != NULL) { - pre_splits.append(clip); - post_splits.append(post_b); - } + if (post_a != NULL) { + pre_splits.append(clip); + post_splits.append(post_a); + } + if (post_b != NULL) { + pre_splits.append(clip); + post_splits.append(post_b); + } - split = true; + split = true; + } } } } @@ -627,8 +661,8 @@ bool Timeline::split_selection() { Clip* pre = pre_splits.at(i); for (int j=0;jlinked.size();k++) { - if (pre->linked.at(k) == pre_splits.at(j)) { - post_splits.at(i)->linked.append(post_splits.at(j)); + if (pre->linked.at(k) == pre_splits.at(j)->id) { + post_splits.at(i)->linked.append(post_splits.at(j)->id); } } } @@ -644,7 +678,7 @@ void Timeline::split_at_playhead() { // see if whole clips are selected for (int j=0;jclip_count();j++) { Clip* clip = sequence->get_clip(j); - if (is_clip_selected(clip)) { + if (clip != NULL && is_clip_selected(clip)) { // should this relink? sequence->split_clip(clip, playhead); split_selected = true; @@ -660,9 +694,12 @@ void Timeline::split_at_playhead() { // if nothing was selected or no selections fell within playhead, simply split at playhead if (!split_selected) { for (int j=0;jclip_count();j++) { - // always relinks - split_clip_and_relink(sequence->get_clip(j), playhead, true); - split_selected = true; + Clip* c = sequence->get_clip(j); + if (c != NULL) { + // always relinks + split_clip_and_relink(sequence->get_clip(j), playhead, true); + split_selected = true; + } } } @@ -686,10 +723,12 @@ void Timeline::snap_to_clip(long* l, bool playhead_inclusive) { if (!playhead_inclusive || !snap_to_point(playhead, l)) { for (int i=0;iclip_count();i++) { Clip* c = sequence->get_clip(i); - if (snap_to_point(c->timeline_in, l)) { - break; - } else if (snap_to_point(c->timeline_out, l)) { - break; + if (c != NULL) { + if (snap_to_point(c->timeline_in, l)) { + break; + } else if (snap_to_point(c->timeline_out, l)) { + break; + } } } } diff --git a/panels/timeline.h b/panels/timeline.h index 08f3aa7a1..0712a2d59 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -69,6 +69,7 @@ public: void split_at_playhead(); void split_clip_and_relink(Clip* clip, long frame, bool relink); void delete_areas_and_relink(QVector& areas); + void relink_clips_using_ids(QVector& old_clips, QVector& new_clips); void update_sequence(); void increase_track_height(); void decrease_track_height(); diff --git a/playback/playback.cpp b/playback/playback.cpp index 5b924d4d8..460c16719 100644 --- a/playback/playback.cpp +++ b/playback/playback.cpp @@ -32,32 +32,34 @@ void handle_media(Sequence* sequence, long playhead, bool multithreaded) { Clip* c = sequence->get_clip(i); // if clip starts within one second and/or hasn't finished yet - if (is_clip_active(c, playhead)) { - // if thread is already working, we don't want to touch this, - // but we also don't want to hang the UI thread - if (!c->open) { - if (c->open_lock.tryLock()) { - open_clip(c, multithreaded); + if (c != NULL) { + if (is_clip_active(c, playhead)) { + // if thread is already working, we don't want to touch this, + // but we also don't want to hang the UI thread + if (!c->open) { + if (c->open_lock.tryLock()) { + open_clip(c, multithreaded); - // add to current_clips, (insertion) sorted by track so composite them in order - cc_lock.lock(); - bool found = false; - for (int j=0;jtrack < c->track) { - current_clips.insert(current_clips.begin()+j, c); - found = true; - break; - } - } - if (!found) { - current_clips.push_back(c); - } - cc_lock.unlock(); - } - } - } else if (c->open) { - close_clip(c); - } + // add to current_clips, (insertion) sorted by track so composite them in order + cc_lock.lock(); + bool found = false; + for (int j=0;jtrack < c->track) { + current_clips.insert(current_clips.begin()+j, c); + found = true; + break; + } + } + if (!found) { + current_clips.push_back(c); + } + cc_lock.unlock(); + } + } + } else if (c->open) { + close_clip(c); + } + } } } @@ -295,7 +297,7 @@ void set_sequence(Sequence* s) { // clean up - close all open clips for (int i=0;iclip_count();i++) { Clip* c = sequence->get_clip(i); - if (c->open) { + if (c != NULL && c->open) { close_clip(c); } } diff --git a/project/clip.cpp b/project/clip.cpp index e954a48d9..f852cea3c 100644 --- a/project/clip.cpp +++ b/project/clip.cpp @@ -19,6 +19,7 @@ Clip* Clip::copy() { Clip* copy = new Clip(); copy->enabled = enabled; + copy->id = id; copy->name = QString(name); copy->clip_in = clip_in; copy->timeline_in = timeline_in; diff --git a/project/clip.h b/project/clip.h index 07e3e85af..fe94310af 100644 --- a/project/clip.h +++ b/project/clip.h @@ -40,6 +40,7 @@ struct Clip // timeline variables bool enabled; + int id; QString name; long clip_in; long timeline_in; @@ -57,7 +58,7 @@ struct Clip // other variables (should be "duplicated" in copy()) QList effects; - QVector linked; + QVector linked; // media handling AVFormatContext* formatCtx; @@ -94,10 +95,6 @@ struct Clip bool reset_audio; bool audio_just_reset; long audio_target_frame; - - // only used for saving/loading - int save_id; - QVector link_ids; }; #endif // CLIP_H diff --git a/project/sequence.cpp b/project/sequence.cpp index 9efe45429..16024228d 100644 --- a/project/sequence.cpp +++ b/project/sequence.cpp @@ -16,6 +16,7 @@ Sequence::~Sequence() { } void Sequence::add_clip(Clip* c) { + c->id = clip_count(); clips.append(c); } @@ -32,7 +33,8 @@ void Sequence::delete_clip(int i) { for (int j=0;jlinked.size();k++) { - if (c->linked[k] == clips[i]) { + if (c->linked[k] == clips[i]->id) { +// c->linked[k] = NULL; c->linked.removeAt(k); break; } @@ -41,15 +43,14 @@ void Sequence::delete_clip(int i) { // finally remove from vector delete clips.at(i); -// clips[i] = NULL; - clips.removeAt(i); + clips[i] = NULL; } long Sequence::getEndFrame() { long end = 0; for (int j=0;jtimeline_out > end) { + if (c != NULL && c->timeline_out > end) { end = c->timeline_out; } } @@ -61,11 +62,13 @@ void Sequence::get_track_limits(int* video_tracks, int* audio_tracks) { int at = 0; for (int j=0;jtrack < 0 && c->track < vt) { // video clip - vt = c->track; - } else if (c->track > at) { - at = c->track; - } + if (c != NULL) { + if (c->track < 0 && c->track < vt) { // video clip + vt = c->track; + } else if (c->track > at) { + at = c->track; + } + } } if (video_tracks != NULL) *video_tracks = vt; if (audio_tracks != NULL) *audio_tracks = at; @@ -91,52 +94,52 @@ Clip* Sequence::split_clip(Clip* pre, long frame) { } void Sequence::undo_add_current() { - if (undo_stack.size() == UNDO_LIMIT) { - delete undo_stack.at(0); - undo_stack.removeFirst(); - } else { - undo_pointer++; - while (undo_stack.size() > undo_pointer+1) { - delete undo_stack.last(); - undo_stack.removeLast(); - } - } +// if (undo_stack.size() == UNDO_LIMIT) { +// delete undo_stack.at(0); +// undo_stack.removeFirst(); +// } else { +// undo_pointer++; +// while (undo_stack.size() > undo_pointer+1) { +// delete undo_stack.last(); +// undo_stack.removeLast(); +// } +// } - // copy clips - QVector* copied_clips = new QVector(); - for (int i=0;iappend(get_clip(i)->copy()); - } - undo_stack.append(copied_clips); +// // copy clips +// QVector* copied_clips = new QVector(); +// for (int i=0;iappend(get_clip(i)->copy()); +// } +// undo_stack.append(copied_clips); } void Sequence::set_undo(int i) { - for (int i=0;i* copy_from_list = undo_stack.at(undo_pointer); - for (int i=0;isize();i++) { - add_clip(copy_from_list->at(i)->copy()); - } +// QVector* copy_from_list = undo_stack.at(undo_pointer); +// for (int i=0;isize();i++) { +// add_clip(copy_from_list->at(i)->copy()); +// } } void Sequence::undo() { - if (undo_pointer > 0) { - undo_pointer--; - set_undo(undo_pointer); - } else { - qDebug() << "[INFO] No more undos"; - } +// if (undo_pointer > 0) { +// undo_pointer--; +// set_undo(undo_pointer); +// } else { +// qDebug() << "[INFO] No more undos"; +// } } void Sequence::redo() { - if (undo_pointer == undo_stack.size() - 1) { - qDebug() << "[INFO] No more redos"; - } else { - undo_pointer++; - set_undo(undo_pointer); - } +// if (undo_pointer == undo_stack.size() - 1) { +// qDebug() << "[INFO] No more redos"; +// } else { +// undo_pointer++; +// set_undo(undo_pointer); +// } } // static variable for the currently active sequence diff --git a/project/sequence.h b/project/sequence.h index bf9b4e1fc..4f7c3b7e3 100644 --- a/project/sequence.h +++ b/project/sequence.h @@ -15,8 +15,7 @@ public: void add_clip(Clip* c); int clip_count(); Clip* get_clip(int i); - void delete_clip(int i); -// void delete_area(long in, long out, int track); + void delete_clip(int i); Clip* split_clip(Clip* pre, long frame); void get_track_limits(int* video_tracks, int* audio_tracks); long getEndFrame(); diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index 95c6de0f3..f90a09748 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -148,7 +148,7 @@ void TimelineWidget::dropEvent(QDropEvent* event) { for (int j=0;jmedia == cc->media) { - c->linked.append(cc); + c->linked.append(cc->id); } } } @@ -198,7 +198,8 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { track_resize_mouse_cache = event->pos().y(); panel_timeline->moving_init = true; } else if (clip_index >= 0) { - if (panel_timeline->is_clip_selected(sequence->get_clip(clip_index))) { + Clip* c = sequence->get_clip(clip_index); + if (c != NULL && panel_timeline->is_clip_selected(c)) { // TODO if shift is down, deselect it } else { // if "shift" is not down @@ -207,14 +208,16 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { } Clip* clip = sequence->get_clip(clip_index); - panel_timeline->selections.append({clip->timeline_in, clip->timeline_out, clip->track}); + if (clip != NULL) { + panel_timeline->selections.append({clip->timeline_in, clip->timeline_out, clip->track}); - // if alt is not down, select links - if (!(event->modifiers() & Qt::AltModifier)) { - for (int i=0;ilinked.size();i++) { - Clip* link = clip->linked.at(i); - if (!panel_timeline->is_clip_selected(link)) { - panel_timeline->selections.append({link->timeline_in, link->timeline_out, link->track}); + // if alt is not down, select links + if (!(event->modifiers() & Qt::AltModifier)) { + for (int i=0;ilinked.size();i++) { + Clip* link = sequence->get_clip(c->linked.at(i)); + if (!panel_timeline->is_clip_selected(link)) { + panel_timeline->selections.append({link->timeline_in, link->timeline_out, link->track}); + } } } } @@ -233,7 +236,8 @@ void TimelineWidget::mousePressEvent(QMouseEvent *event) { case TIMELINE_TOOL_RAZOR: { if (clip_index >= 0) { - panel_timeline->split_clip_and_relink(sequence->get_clip(clip_index), panel_timeline->drag_frame_start, !(event->modifiers() & Qt::AltModifier)); + Clip* clip = sequence->get_clip(clip_index); + if (clip != NULL) panel_timeline->split_clip_and_relink(clip, panel_timeline->drag_frame_start, !(event->modifiers() & Qt::AltModifier)); } panel_timeline->splitting = true; panel_timeline->redraw_all_clips(true); @@ -248,6 +252,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { if (panel_timeline->moving_proc) { if (event->modifiers() & Qt::AltModifier) { // if holding alt, duplicate rather than move // duplicate clips + QVector old_clips; QVector copy_clips; QVector delete_areas; for (int i=0;ighosts.size();i++) { @@ -261,6 +266,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { delete_areas.append({g.in, g.out, g.track}); + old_clips.append(g.clip); copy_clips.append(c); } } @@ -270,6 +276,8 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { // step 2 - delete anything that exists in area that clip is moving to sequence->add_clip(copy_clips.at(i)); } + // relink duplicated clips + panel_timeline->relink_clips_using_ids(old_clips, copy_clips); } } else { // move clips @@ -355,7 +363,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { Clip* aclip = NULL; for (int i=0;iclip_count();i++) { Clip* clip = sequence->get_clip(i); - if (panel_timeline->is_clip_selected(clip)) { + if (clip != NULL && panel_timeline->is_clip_selected(clip)) { if (clip->track < 0) { if (got_vclip) { vclip = NULL; @@ -380,7 +388,7 @@ void TimelineWidget::mouseReleaseEvent(QMouseEvent *event) { if (vclip != NULL && aclip != NULL) { bool found = false; for (int i=0;ilinked.size();i++) { - if (vclip->linked.at(i) == aclip) { + if (vclip->linked.at(i) == aclip->id) { found = true; break; } @@ -441,10 +449,12 @@ void validate_snapping(Ghost& g, long* frame_diff) { if (!subvalidate_snapping(g, frame_diff, panel_timeline->playhead)) { for (int j=0;jclip_count();j++) { Clip* c = sequence->get_clip(j); - if (!subvalidate_snapping(g, frame_diff, c->timeline_in)) { - subvalidate_snapping(g, frame_diff, c->timeline_out); + if (c != NULL) { + if (!subvalidate_snapping(g, frame_diff, c->timeline_in)) { + subvalidate_snapping(g, frame_diff, c->timeline_out); + } + if (panel_timeline->snapped) break; } - if (panel_timeline->snapped) break; } } } @@ -682,7 +692,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { // create ghosts for (int i=0;iclip_count();i++) { Clip* c = sequence->get_clip(i); - if (panel_timeline->is_clip_selected(c)) { + if (c != NULL && panel_timeline->is_clip_selected(c)) { panel_timeline->ghosts.append({c, c->timeline_in, c->timeline_out, c->track, c->clip_in}); } } @@ -692,54 +702,57 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { for (int i=0;ighosts.size();i++) { // get clips before and after ripple point for (int j=0;jclip_count();j++) { - // don't cache any currently selected clips - Clip* c = panel_timeline->ghosts.at(i).clip; Clip* cc = sequence->get_clip(j); - bool is_selected = false; - for (int k=0;kghosts.size();k++) { - if (panel_timeline->ghosts.at(k).clip == cc) { - is_selected = true; - break; - } - } - if (!is_selected) { - if (cc->timeline_in < c->timeline_in) { - // add clip to pre-cache UNLESS there is already a clip on that track closer to the ripple point - bool found = false; - for (int k=0;ktrack == cc->track) { - if (ccc->timeline_in < cc->timeline_in) { - // clip is closer to ripple point than the one in cache, replace it - ccc = cc; - } - found = true; - } - } - if (!found) { - // no clip from that track in the cache, add it - pre_clips.append(cc); - } - } else { - // add clip to post-cache UNLESS there is already a clip on that track closer to the ripple point - bool found = false; - for (int k=0;ktrack == cc->track) { - if (ccc->timeline_in > cc->timeline_in) { - // clip is closer to ripple point than the one in cache, replace it - ccc = cc; - } - found = true; - } - } - if (!found) { - // no clip from that track in the cache, add it - post_clips.append(cc); - } - } - } + if (cc != NULL) { + // don't cache any currently selected clips + Clip* c = panel_timeline->ghosts.at(i).clip; + bool is_selected = false; + for (int k=0;kghosts.size();k++) { + if (panel_timeline->ghosts.at(k).clip == cc) { + is_selected = true; + break; + } + } + + if (!is_selected) { + if (cc->timeline_in < c->timeline_in) { + // add clip to pre-cache UNLESS there is already a clip on that track closer to the ripple point + bool found = false; + for (int k=0;ktrack == cc->track) { + if (ccc->timeline_in < cc->timeline_in) { + // clip is closer to ripple point than the one in cache, replace it + ccc = cc; + } + found = true; + } + } + if (!found) { + // no clip from that track in the cache, add it + pre_clips.append(cc); + } + } else { + // add clip to post-cache UNLESS there is already a clip on that track closer to the ripple point + bool found = false; + for (int k=0;ktrack == cc->track) { + if (ccc->timeline_in > cc->timeline_in) { + // clip is closer to ripple point than the one in cache, replace it + ccc = cc; + } + found = true; + } + } + if (!found) { + // no clip from that track in the cache, add it + post_clips.append(cc); + } + } + } + } } } } @@ -754,7 +767,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { bool repaint = false; for (int i=0;iclip_count();i++) { Clip* clip = sequence->get_clip(i); - if (clip->track == track) { + if (clip != NULL && clip->track == track) { panel_timeline->split_clip_and_relink(clip, panel_timeline->drag_frame_start, !(event->modifiers() & Qt::AltModifier)); repaint = true; } @@ -775,7 +788,7 @@ void TimelineWidget::mouseMoveEvent(QMouseEvent *event) { int closeness = INT_MAX; for (int i=0;iclip_count();i++) { Clip* c = sequence->get_clip(i); - if (c->track == mouse_track) { + if (c != NULL && c->track == mouse_track) { if (c->timeline_in > mouse_frame_lower && c->timeline_in < mouse_frame_upper) { int nc = abs(c->timeline_in + 1 - panel_timeline->cursor_frame); if (nc < closeness) { @@ -855,7 +868,7 @@ void TimelineWidget::redraw_clips() { int audio_track_limit = 0; for (int i=0;iclip_count();i++) { Clip* clip = sequence->get_clip(i); - if (is_track_visible(clip->track)) { + if (clip != NULL && is_track_visible(clip->track)) { if (clip->track < 0 && clip->track < video_track_limit) { // video clip video_track_limit = clip->track; } else if (clip->track > audio_track_limit) { @@ -1068,7 +1081,7 @@ int TimelineWidget::getScreenPointFromTrack(int track) { int TimelineWidget::getClipIndexFromCoords(long frame, int track) { for (int i=0;iclip_count();i++) { Clip* c = sequence->get_clip(i); - if (c->track == track) { + if (c != NULL && c->track == track) { if (frame >= c->timeline_in && frame < c->timeline_out) { return i; }