further work on timeline rewrite
This commit is contained in:
@@ -639,10 +639,10 @@ void EffectControls::Load() {
|
||||
|
||||
QVBoxLayout* layout;
|
||||
|
||||
if (c->track() < 0) {
|
||||
if (c->type() == Track::kTypeVideo) {
|
||||
vcontainer->setVisible(true);
|
||||
layout = video_effect_layout;
|
||||
} else {
|
||||
} else if (c->type() == Track::kTypeAudio) {
|
||||
acontainer->setVisible(true);
|
||||
layout = audio_effect_layout;
|
||||
}
|
||||
|
||||
+7
-8
@@ -449,7 +449,7 @@ void Project::delete_selected_media() {
|
||||
}
|
||||
}
|
||||
if (confirm_delete) {
|
||||
ca->append(new DeleteClipAction(s, k));
|
||||
ca->append(new DeleteClipAction(c));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -589,13 +589,12 @@ void Project::delete_clips_using_selected_media() {
|
||||
QVector<Clip*> sequence_clips = olive::ActiveSequence->GetAllClips();
|
||||
for (int i=0;i<sequence_clips.size();i++) {
|
||||
Clip* c = sequence_clips.at(i);
|
||||
if (c != nullptr) {
|
||||
for (int j=0;j<items.size();j++) {
|
||||
Media* m = item_to_media(items.at(j));
|
||||
if (c->media() == m) {
|
||||
ca->append(new DeleteClipAction(olive::ActiveSequence.get(), i));
|
||||
deleted = true;
|
||||
}
|
||||
|
||||
for (int j=0;j<items.size();j++) {
|
||||
Media* m = item_to_media(items.at(j));
|
||||
if (c->media() == m) {
|
||||
ca->append(new DeleteClipAction(c));
|
||||
deleted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+82
-403
@@ -33,6 +33,7 @@
|
||||
#include <QHBoxLayout>
|
||||
#include <QSplitter>
|
||||
#include <QStatusBar>
|
||||
#include <QButtonGroup>
|
||||
|
||||
#include "global/global.h"
|
||||
#include "panels/panels.h"
|
||||
@@ -90,9 +91,7 @@ Timeline::Timeline(QWidget *parent) :
|
||||
|
||||
headers->viewer = panel_sequence_viewer;
|
||||
|
||||
video_area->bottom_align = true;
|
||||
video_area->scrollBar = videoScrollbar;
|
||||
audio_area->scrollBar = audioScrollbar;
|
||||
video_area->SetAlignment(olive::timeline::kAlignmentBottom);
|
||||
|
||||
tool_buttons.append(toolArrowButton);
|
||||
tool_buttons.append(toolEditButton);
|
||||
@@ -103,11 +102,21 @@ Timeline::Timeline(QWidget *parent) :
|
||||
tool_buttons.append(toolTransitionButton);
|
||||
tool_buttons.append(toolHandButton);
|
||||
|
||||
tool_button_group = new QButtonGroup(this);
|
||||
tool_button_group->addButton(toolArrowButton);
|
||||
tool_button_group->addButton(toolEditButton);
|
||||
tool_button_group->addButton(toolRippleButton);
|
||||
tool_button_group->addButton(toolRazorButton);
|
||||
tool_button_group->addButton(toolSlipButton);
|
||||
tool_button_group->addButton(toolSlideButton);
|
||||
tool_button_group->addButton(toolTransitionButton);
|
||||
tool_button_group->addButton(toolHandButton);
|
||||
|
||||
toolArrowButton->click();
|
||||
|
||||
connect(horizontalScrollBar, SIGNAL(valueChanged(int)), this, SLOT(setScroll(int)));
|
||||
connect(videoScrollbar, SIGNAL(valueChanged(int)), video_area, SLOT(setScroll(int)));
|
||||
connect(audioScrollbar, SIGNAL(valueChanged(int)), audio_area, SLOT(setScroll(int)));
|
||||
//connect(videoScrollbar, SIGNAL(valueChanged(int)), video_area, SLOT(setScroll(int)));
|
||||
//connect(audioScrollbar, SIGNAL(valueChanged(int)), audio_area, SLOT(setScroll(int)));
|
||||
connect(horizontalScrollBar, SIGNAL(resize_move(double)), this, SLOT(resize_move(double)));
|
||||
|
||||
update_sequence();
|
||||
@@ -133,91 +142,6 @@ void Timeline::Retranslate() {
|
||||
UpdateTitle();
|
||||
}
|
||||
|
||||
void Timeline::split_clip_at_positions(ComboAction* ca, int clip_index, QVector<long> positions) {
|
||||
|
||||
QVector<int> pre_splits;
|
||||
|
||||
// Add the clip and each of its links to the pre_splits array
|
||||
Clip* clip = olive::ActiveSequence->clips.at(clip_index).get();
|
||||
pre_splits.append(clip_index);
|
||||
for (int i=0;i<clip->linked.size();i++) {
|
||||
pre_splits.append(clip->linked.at(i));
|
||||
}
|
||||
|
||||
std::sort(positions.begin(), positions.end());
|
||||
|
||||
// Remove any duplicate positions
|
||||
for (int i=1;i<positions.size();i++) {
|
||||
if (positions.at(i-1) == positions.at(i)) {
|
||||
positions.removeAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=1;i<positions.size();i++) {
|
||||
Q_ASSERT(positions.at(i-1) < positions.at(i));
|
||||
}
|
||||
|
||||
QVector< QVector<ClipPtr> > post_splits(positions.size());
|
||||
|
||||
for (int i=positions.size()-1;i>=0;i--) {
|
||||
|
||||
post_splits[i].resize(pre_splits.size());
|
||||
|
||||
for (int j=0;j<pre_splits.size();j++) {
|
||||
post_splits[i][j] = split_clip(ca, true, pre_splits.at(j), positions.at(i));
|
||||
|
||||
if (post_splits[i][j] != nullptr && i + 1 < positions.size()) {
|
||||
post_splits[i][j]->set_timeline_out(positions.at(i+1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0;i<post_splits.size();i++) {
|
||||
relink_clips_using_ids(pre_splits, post_splits[i]);
|
||||
ca->append(new AddClipCommand(olive::ActiveSequence.get(), post_splits[i]));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Timeline::previous_cut() {
|
||||
if (olive::ActiveSequence != nullptr
|
||||
&& olive::ActiveSequence->playhead > 0) {
|
||||
long p_cut = 0;
|
||||
for (int i=0;i<olive::ActiveSequence->clips.size();i++) {
|
||||
ClipPtr c = olive::ActiveSequence->clips.at(i);
|
||||
if (c != nullptr) {
|
||||
if (c->timeline_out() > p_cut && c->timeline_out() < olive::ActiveSequence->playhead) {
|
||||
p_cut = c->timeline_out();
|
||||
} else if (c->timeline_in() > p_cut && c->timeline_in() < olive::ActiveSequence->playhead) {
|
||||
p_cut = c->timeline_in();
|
||||
}
|
||||
}
|
||||
}
|
||||
panel_sequence_viewer->seek(p_cut);
|
||||
}
|
||||
}
|
||||
|
||||
void Timeline::next_cut() {
|
||||
if (olive::ActiveSequence != nullptr) {
|
||||
bool seek_enabled = false;
|
||||
long n_cut = LONG_MAX;
|
||||
for (int i=0;i<olive::ActiveSequence->clips.size();i++) {
|
||||
ClipPtr c = olive::ActiveSequence->clips.at(i);
|
||||
if (c != nullptr) {
|
||||
if (c->timeline_in() < n_cut && c->timeline_in() > olive::ActiveSequence->playhead) {
|
||||
n_cut = c->timeline_in();
|
||||
seek_enabled = true;
|
||||
} else if (c->timeline_out() < n_cut && c->timeline_out() > olive::ActiveSequence->playhead) {
|
||||
n_cut = c->timeline_out();
|
||||
seek_enabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (seek_enabled) panel_sequence_viewer->seek(n_cut);
|
||||
}
|
||||
}
|
||||
|
||||
void ripple_clips(ComboAction* ca, Sequence* s, long point, long length, const QVector<int>& ignore) {
|
||||
ca->append(new RippleAction(s, point, length, ignore));
|
||||
}
|
||||
@@ -227,7 +151,7 @@ void Timeline::toggle_show_all() {
|
||||
showing_all = !showing_all;
|
||||
if (showing_all) {
|
||||
old_zoom = zoom;
|
||||
set_zoom_value(double(timeline_area->width() - 200) / double(olive::ActiveSequence->getEndFrame()));
|
||||
set_zoom_value(double(timeline_area->width() - 200) / double(olive::ActiveSequence->GetEndFrame()));
|
||||
} else {
|
||||
set_zoom_value(old_zoom);
|
||||
}
|
||||
@@ -302,7 +226,7 @@ void Timeline::create_ghosts_from_media(Sequence* seq, long entry_point, QVector
|
||||
|| import_data.type() == olive::timeline::kImportBoth) {
|
||||
for (int j=0;j<m->audio_tracks.size();j++) {
|
||||
if (m->audio_tracks.at(j).enabled) {
|
||||
g.track = j;
|
||||
g.track = seq->GetTrackList(Track::kTypeAudio)->First() + j;
|
||||
g.media_stream = m->audio_tracks.at(j).file_index;
|
||||
ghosts.append(g);
|
||||
audio_ghosts = true;
|
||||
@@ -314,7 +238,7 @@ void Timeline::create_ghosts_from_media(Sequence* seq, long entry_point, QVector
|
||||
|| import_data.type() == olive::timeline::kImportBoth) {
|
||||
for (int j=0;j<m->video_tracks.size();j++) {
|
||||
if (m->video_tracks.at(j).enabled) {
|
||||
g.track = -1-j;
|
||||
g.track = seq->GetTrackList(Track::kTypeVideo)->First() + j;
|
||||
g.media_stream = m->video_tracks.at(j).file_index;
|
||||
ghosts.append(g);
|
||||
video_ghosts = true;
|
||||
@@ -331,13 +255,13 @@ void Timeline::create_ghosts_from_media(Sequence* seq, long entry_point, QVector
|
||||
|
||||
if (import_data.type() == olive::timeline::kImportVideoOnly
|
||||
|| import_data.type() == olive::timeline::kImportBoth) {
|
||||
g.track = -1;
|
||||
g.track = seq->GetTrackList(Track::kTypeVideo)->First();
|
||||
ghosts.append(g);
|
||||
}
|
||||
|
||||
if (import_data.type() == olive::timeline::kImportAudioOnly
|
||||
|| import_data.type() == olive::timeline::kImportBoth) {
|
||||
g.track = 0;
|
||||
g.track = seq->GetTrackList(Track::kTypeAudio)->First();
|
||||
ghosts.append(g);
|
||||
}
|
||||
|
||||
@@ -401,15 +325,15 @@ void Timeline::add_clips_from_ghosts(ComboAction* ca, Sequence* s) {
|
||||
for (int j=0;j<added_clips.size();j++) {
|
||||
ClipPtr cc = added_clips.at(j);
|
||||
if (c != cc && c->media() == cc->media()) {
|
||||
c->linked.append(j);
|
||||
c->linked.append(cc.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (olive::CurrentConfig.add_default_effects_to_clips) {
|
||||
if (c->track() < 0) {
|
||||
if (c->type() == Track::kTypeVideo) {
|
||||
// add default video effects
|
||||
c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_TRANSFORM, EFFECT_TYPE_EFFECT)));
|
||||
} else {
|
||||
} else if (c->type() == Track::kTypeAudio) {
|
||||
// add default audio effects
|
||||
c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_VOLUME, EFFECT_TYPE_EFFECT)));
|
||||
c->effects.append(Effect::Create(c.get(), Effect::GetInternalMeta(EFFECT_INTERNAL_PAN, EFFECT_TYPE_EFFECT)));
|
||||
@@ -428,26 +352,30 @@ void Timeline::add_transition() {
|
||||
ComboAction* ca = new ComboAction();
|
||||
bool adding = false;
|
||||
|
||||
for (int i=0;i<olive::ActiveSequence->clips.size();i++) {
|
||||
Clip* c = olive::ActiveSequence->clips.at(i).get();
|
||||
if (c != nullptr && c->IsSelected()) {
|
||||
int transition_to_add = (c->track() < 0) ? TRANSITION_INTERNAL_CROSSDISSOLVE : TRANSITION_INTERNAL_LINEARFADE;
|
||||
if (c->opening_transition == nullptr) {
|
||||
ca->append(new AddTransitionCommand(c,
|
||||
nullptr,
|
||||
nullptr,
|
||||
Effect::GetInternalMeta(transition_to_add, EFFECT_TYPE_TRANSITION),
|
||||
olive::CurrentConfig.default_transition_length));
|
||||
adding = true;
|
||||
}
|
||||
if (c->closing_transition == nullptr) {
|
||||
ca->append(new AddTransitionCommand(nullptr,
|
||||
c,
|
||||
nullptr,
|
||||
Effect::GetInternalMeta(transition_to_add, EFFECT_TYPE_TRANSITION),
|
||||
olive::CurrentConfig.default_transition_length));
|
||||
adding = true;
|
||||
}
|
||||
QVector<Clip*> selected_clips = olive::ActiveSequence->SelectedClips();
|
||||
|
||||
for (int i=0;i<selected_clips.size();i++) {
|
||||
Clip* c = selected_clips.at(i);
|
||||
|
||||
int transition_to_add = (c->type() == Track::kTypeVideo) ? TRANSITION_INTERNAL_CROSSDISSOLVE
|
||||
: TRANSITION_INTERNAL_LINEARFADE;
|
||||
|
||||
if (c->opening_transition == nullptr) {
|
||||
ca->append(new AddTransitionCommand(c,
|
||||
nullptr,
|
||||
nullptr,
|
||||
Effect::GetInternalMeta(transition_to_add, EFFECT_TYPE_TRANSITION),
|
||||
olive::CurrentConfig.default_transition_length));
|
||||
adding = true;
|
||||
}
|
||||
|
||||
if (c->closing_transition == nullptr) {
|
||||
ca->append(new AddTransitionCommand(nullptr,
|
||||
c,
|
||||
nullptr,
|
||||
Effect::GetInternalMeta(transition_to_add, EFFECT_TYPE_TRANSITION),
|
||||
olive::CurrentConfig.default_transition_length));
|
||||
adding = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,7 +391,7 @@ void Timeline::add_transition() {
|
||||
void Timeline::nest() {
|
||||
if (olive::ActiveSequence != nullptr) {
|
||||
// get selected clips
|
||||
QVector<int> selected_clips = olive::ActiveSequence->SelectedClipIndexes();
|
||||
QVector<Clip*> selected_clips = olive::ActiveSequence->SelectedClips();
|
||||
|
||||
// nest them
|
||||
if (!selected_clips.isEmpty()) {
|
||||
@@ -471,7 +399,7 @@ void Timeline::nest() {
|
||||
// get earliest point in selected clips
|
||||
long earliest_point = LONG_MAX;
|
||||
for (int i=0;i<selected_clips.size();i++) {
|
||||
earliest_point = qMin(olive::ActiveSequence->clips.at(selected_clips.at(i))->timeline_in(), earliest_point);
|
||||
earliest_point = qMin(selected_clips.first()->timeline_in(), earliest_point);
|
||||
}
|
||||
|
||||
ComboAction* ca = new ComboAction();
|
||||
@@ -479,30 +407,37 @@ void Timeline::nest() {
|
||||
// create "nest" sequence with the same attributes as the current sequence
|
||||
SequencePtr s = std::make_shared<Sequence>();
|
||||
|
||||
s->name = panel_project->get_next_sequence_name(tr("Nested Sequence"));
|
||||
s->name = olive::project_model.GetNextSequenceName(tr("Nested Sequence"));
|
||||
s->width = olive::ActiveSequence->width;
|
||||
s->height = olive::ActiveSequence->height;
|
||||
s->frame_rate = olive::ActiveSequence->frame_rate;
|
||||
s->audio_frequency = olive::ActiveSequence->audio_frequency;
|
||||
s->audio_layout = olive::ActiveSequence->audio_layout;
|
||||
|
||||
QVector<ClipPtr> new_clips;
|
||||
|
||||
// copy all selected clips to the nest
|
||||
for (int i=0;i<selected_clips.size();i++) {
|
||||
Clip* c = selected_clips.at(i);
|
||||
|
||||
// delete clip from old sequence
|
||||
ca->append(new DeleteClipAction(olive::ActiveSequence.get(), selected_clips.at(i)));
|
||||
ca->append(new DeleteClipAction(c));
|
||||
|
||||
// copy to new
|
||||
ClipPtr copy(olive::ActiveSequence->clips.at(selected_clips.at(i))->copy(s.get()));
|
||||
Track* track = s->GetTrackList(c->type())->TrackAt(c->track()->Index());
|
||||
ClipPtr copy = selected_clips.at(i)->copy(track);
|
||||
copy->set_timeline_in(copy->timeline_in() - earliest_point);
|
||||
copy->set_timeline_out(copy->timeline_out() - earliest_point);
|
||||
s->clips.append(copy);
|
||||
track->AddClip(copy);
|
||||
|
||||
new_clips.append(copy);
|
||||
}
|
||||
|
||||
// relink clips in new nested sequences
|
||||
relink_clips_using_ids(selected_clips, s->clips);
|
||||
olive::timeline::RelinkClips(selected_clips, new_clips);
|
||||
|
||||
// add sequence to project
|
||||
MediaPtr m = panel_project->create_sequence_internal(ca, s, false, nullptr);
|
||||
MediaPtr m = olive::project_model.CreateSequence(ca, s, false, nullptr);
|
||||
|
||||
// add nested sequence to active sequence
|
||||
QVector<olive::timeline::MediaImportData> media_list;
|
||||
@@ -510,9 +445,10 @@ void Timeline::nest() {
|
||||
create_ghosts_from_media(olive::ActiveSequence.get(), earliest_point, media_list);
|
||||
|
||||
// ensure ghosts won't overlap anything
|
||||
for (int j=0;j<olive::ActiveSequence->clips.size();j++) {
|
||||
Clip* c = olive::ActiveSequence->clips.at(j).get();
|
||||
if (c != nullptr && !selected_clips.contains(j)) {
|
||||
QVector<Clip*> all_sequence_clips = olive::ActiveSequence->GetAllClips();
|
||||
for (int j=0;j<all_sequence_clips.size();j++) {
|
||||
Clip* c = all_sequence_clips.at(j);
|
||||
if (!selected_clips.contains(c)) {
|
||||
for (int i=0;i<ghosts.size();i++) {
|
||||
Ghost& g = ghosts[i];
|
||||
if (c->track() == g.track
|
||||
@@ -520,14 +456,14 @@ void Timeline::nest() {
|
||||
&& c->timeline_out() < g.in)
|
||||
|| (c->timeline_in() > g.out
|
||||
&& c->timeline_out() > g.out))) {
|
||||
// There's a clip occupied by the space taken up by this ghost. Move up/down a track, and seek again
|
||||
if (g.track < 0) {
|
||||
g.track--;
|
||||
} else {
|
||||
g.track++;
|
||||
}
|
||||
|
||||
// There's a clip occupied by the space taken up by this ghost. Move up a track, and seek again.
|
||||
g.track = g.track->track_list()->TrackAt(g.track->Index() + 1);
|
||||
|
||||
// Restart entire loop again
|
||||
j = -1;
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -538,7 +474,7 @@ void Timeline::nest() {
|
||||
|
||||
panel_graph_editor->set_row(nullptr);
|
||||
panel_effect_controls->Clear(true);
|
||||
olive::ActiveSequence->selections.clear();
|
||||
olive::ActiveSequence->ClearSelections();
|
||||
|
||||
olive::UndoStack.push(ca);
|
||||
|
||||
@@ -551,7 +487,7 @@ void Timeline::update_sequence() {
|
||||
bool null_sequence = (olive::ActiveSequence == nullptr);
|
||||
|
||||
for (int i=0;i<tool_buttons.count();i++) {
|
||||
tool_buttons[i]->setEnabled(!null_sequence);
|
||||
tool_buttons.at(i)->setEnabled(!null_sequence);
|
||||
}
|
||||
snappingButton->setEnabled(!null_sequence);
|
||||
zoomInButton->setEnabled(!null_sequence);
|
||||
@@ -563,7 +499,7 @@ void Timeline::update_sequence() {
|
||||
UpdateTitle();
|
||||
}
|
||||
|
||||
int Timeline::get_snap_range() {
|
||||
long Timeline::get_snap_range() {
|
||||
return getFrameFromScreenPoint(zoom, 10);
|
||||
}
|
||||
|
||||
@@ -583,7 +519,7 @@ void Timeline::repaint_timeline() {
|
||||
// auto scroll
|
||||
if (olive::CurrentConfig.autoscroll == olive::AUTOSCROLL_PAGE_SCROLL) {
|
||||
int playhead_x = getTimelineScreenPointFromFrame(olive::ActiveSequence->playhead);
|
||||
if (playhead_x < 0 || playhead_x > (editAreas->width() - videoScrollbar->width())) {
|
||||
if (playhead_x < 0 || playhead_x > (editAreas->width())) {
|
||||
horizontalScrollBar->setValue(getScreenPointFromFrame(zoom, olive::ActiveSequence->playhead));
|
||||
draw = false;
|
||||
}
|
||||
@@ -611,7 +547,7 @@ void Timeline::repaint_timeline() {
|
||||
|
||||
void Timeline::select_all() {
|
||||
if (olive::ActiveSequence != nullptr) {
|
||||
olive::ActiveSequence->selections.clear();
|
||||
olive::ActiveSequence->ClearSelections();
|
||||
for (int i=0;i<olive::ActiveSequence->clips.size();i++) {
|
||||
ClipPtr c = olive::ActiveSequence->clips.at(i);
|
||||
if (c != nullptr) {
|
||||
@@ -864,12 +800,6 @@ void Timeline::multiply_zoom(double m) {
|
||||
set_zoom_value(zoom * m);
|
||||
}
|
||||
|
||||
void Timeline::decheck_tool_buttons(QObject* sender) {
|
||||
for (int i=0;i<tool_buttons.count();i++) {
|
||||
tool_buttons[i]->setChecked(tool_buttons.at(i) == sender);
|
||||
}
|
||||
}
|
||||
|
||||
void Timeline::zoom_in() {
|
||||
multiply_zoom(2.0);
|
||||
}
|
||||
@@ -928,83 +858,7 @@ void Timeline::snapping_clicked(bool checked) {
|
||||
snapping = checked;
|
||||
}
|
||||
|
||||
ClipPtr Timeline::split_clip(ComboAction* ca, bool transitions, int p, long frame) {
|
||||
return split_clip(ca, transitions, p, frame, frame);
|
||||
}
|
||||
|
||||
ClipPtr Timeline::split_clip(ComboAction* ca, bool transitions, int p, long frame, long post_in) {
|
||||
Clip* pre = olive::ActiveSequence->clips.at(p).get();
|
||||
if (pre != nullptr) {
|
||||
|
||||
if (pre->timeline_in() < frame && pre->timeline_out() > frame) {
|
||||
// duplicate clip without duplicating its transitions, we'll restore them later
|
||||
|
||||
ClipPtr post = pre->copy(olive::ActiveSequence.get());
|
||||
|
||||
long new_clip_length = frame - pre->timeline_in();
|
||||
|
||||
post->set_timeline_in(post_in);
|
||||
post->set_clip_in(pre->clip_in() + (post->timeline_in() - pre->timeline_in()));
|
||||
|
||||
pre->move(ca, pre->timeline_in(), frame, pre->clip_in(), pre->track(), false);
|
||||
|
||||
if (transitions) {
|
||||
|
||||
// check if this clip has a closing transition
|
||||
if (pre->closing_transition != nullptr) {
|
||||
|
||||
// if so, move closing transition to the post clip
|
||||
post->closing_transition = pre->closing_transition;
|
||||
|
||||
// and set the original clip's closing transition to nothing
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&pre->closing_transition), nullptr));
|
||||
|
||||
// and set the transition's reference to the post clip
|
||||
if (post->closing_transition->parent_clip == pre) {
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&post->closing_transition->parent_clip), post.get()));
|
||||
}
|
||||
if (post->closing_transition->secondary_clip == pre) {
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&post->closing_transition->secondary_clip), post.get()));
|
||||
}
|
||||
|
||||
// and make sure it's at the correct size to the closing clip
|
||||
if (post->closing_transition != nullptr && post->closing_transition->get_true_length() > post->length()) {
|
||||
ca->append(new ModifyTransitionCommand(post->closing_transition, post->length()));
|
||||
post->closing_transition->set_length(post->length());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// we're keeping the opening clip, so ensure that's a correct size too
|
||||
if (pre->opening_transition != nullptr && pre->opening_transition->get_true_length() > new_clip_length) {
|
||||
ca->append(new ModifyTransitionCommand(pre->opening_transition, new_clip_length));
|
||||
}
|
||||
}
|
||||
|
||||
return post;
|
||||
|
||||
} else if (frame == pre->timeline_in()
|
||||
&& pre->opening_transition != nullptr
|
||||
&& pre->opening_transition->secondary_clip != nullptr) {
|
||||
// special case for shared transitions to split it into two
|
||||
|
||||
// set transition to single-clip mode
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&pre->opening_transition->secondary_clip), nullptr));
|
||||
|
||||
// clone transition for other clip
|
||||
ca->append(new AddTransitionCommand(nullptr,
|
||||
pre->opening_transition->secondary_clip,
|
||||
pre->opening_transition,
|
||||
nullptr,
|
||||
0)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/*
|
||||
bool Timeline::split_clip_and_relink(ComboAction *ca, int clip, long frame, bool relink) {
|
||||
Clip* c = olive::ActiveSequence->clips.at(clip).get();
|
||||
if (c != nullptr) {
|
||||
@@ -1045,121 +899,9 @@ bool Timeline::split_clip_and_relink(ComboAction *ca, int clip, long frame, bool
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
|
||||
void Timeline::clean_up_selections(QVector<Selection>& areas) {
|
||||
for (int i=0;i<areas.size();i++) {
|
||||
Selection& s = areas[i];
|
||||
for (int j=0;j<areas.size();j++) {
|
||||
if (i != j) {
|
||||
Selection& ss = areas[j];
|
||||
if (s.track == ss.track) {
|
||||
bool remove = false;
|
||||
if (s.in < ss.in && s.out > ss.out) {
|
||||
// do nothing
|
||||
} else if (s.in >= ss.in && s.out <= ss.out) {
|
||||
remove = true;
|
||||
} else if (s.in <= ss.out && s.out > ss.out) {
|
||||
ss.out = s.out;
|
||||
remove = true;
|
||||
} else if (s.out >= ss.in && s.in < ss.in) {
|
||||
ss.in = s.in;
|
||||
remove = true;
|
||||
}
|
||||
if (remove) {
|
||||
areas.removeAt(i);
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool selection_contains_transition(const Selection& s, Clip* c, int type) {
|
||||
if (type == kTransitionOpening) {
|
||||
return c->opening_transition != nullptr
|
||||
&& s.out == c->timeline_in() + c->opening_transition->get_true_length()
|
||||
&& ((c->opening_transition->secondary_clip == nullptr && s.in == c->timeline_in())
|
||||
|| (c->opening_transition->secondary_clip != nullptr && s.in == c->timeline_in() - c->opening_transition->get_true_length()));
|
||||
} else {
|
||||
return c->closing_transition != nullptr
|
||||
&& s.in == c->timeline_out() - c->closing_transition->get_true_length()
|
||||
&& ((c->closing_transition->secondary_clip == nullptr && s.out == c->timeline_out())
|
||||
|| (c->closing_transition->secondary_clip != nullptr && s.out == c->timeline_out() + c->closing_transition->get_true_length()));
|
||||
}
|
||||
}
|
||||
|
||||
void Timeline::delete_areas_and_relink(ComboAction* ca, QVector<Selection>& areas, bool deselect_areas) {
|
||||
clean_up_selections(areas);
|
||||
|
||||
panel_graph_editor->set_row(nullptr);
|
||||
panel_effect_controls->Clear(true);
|
||||
|
||||
QVector<int> pre_clips;
|
||||
QVector<ClipPtr> post_clips;
|
||||
|
||||
for (int i=0;i<areas.size();i++) {
|
||||
const Selection& s = areas.at(i);
|
||||
for (int j=0;j<olive::ActiveSequence->clips.size();j++) {
|
||||
Clip* c = olive::ActiveSequence->clips.at(j).get();
|
||||
if (c != nullptr && c->track() == s.track && !c->undeletable) {
|
||||
if (selection_contains_transition(s, c, kTransitionOpening)) {
|
||||
// delete opening transition
|
||||
ca->append(new DeleteTransitionCommand(c->opening_transition));
|
||||
} else if (selection_contains_transition(s, c, kTransitionClosing)) {
|
||||
// delete closing transition
|
||||
ca->append(new DeleteTransitionCommand(c->closing_transition));
|
||||
} else if (c->timeline_in() >= s.in && c->timeline_out() <= s.out) {
|
||||
// clips falls entirely within deletion area
|
||||
ca->append(new DeleteClipAction(olive::ActiveSequence.get(), j));
|
||||
} else if (c->timeline_in() < s.in && c->timeline_out() > s.out) {
|
||||
// middle of clip is within deletion area
|
||||
|
||||
// duplicate clip
|
||||
ClipPtr post = split_clip(ca, true, j, s.in, s.out);
|
||||
|
||||
pre_clips.append(j);
|
||||
post_clips.append(post);
|
||||
} else if (c->timeline_in() < s.in && c->timeline_out() > s.in) {
|
||||
// only out point is in deletion area
|
||||
c->move(ca, c->timeline_in(), s.in, c->clip_in(), c->track());
|
||||
|
||||
if (c->closing_transition != nullptr) {
|
||||
if (s.in < c->timeline_out() - c->closing_transition->get_true_length()) {
|
||||
ca->append(new DeleteTransitionCommand(c->closing_transition));
|
||||
} else {
|
||||
ca->append(new ModifyTransitionCommand(c->closing_transition, c->closing_transition->get_true_length() - (c->timeline_out() - s.in)));
|
||||
}
|
||||
}
|
||||
} else if (c->timeline_in() < s.out && c->timeline_out() > s.out) {
|
||||
// only in point is in deletion area
|
||||
c->move(ca, s.out, c->timeline_out(), c->clip_in() + (s.out - c->timeline_in()), c->track());
|
||||
|
||||
if (c->opening_transition != nullptr) {
|
||||
if (s.out > c->timeline_in() + c->opening_transition->get_true_length()) {
|
||||
ca->append(new DeleteTransitionCommand(c->opening_transition));
|
||||
} else {
|
||||
ca->append(new ModifyTransitionCommand(c->opening_transition, c->opening_transition->get_true_length() - (s.out - c->timeline_in())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// deselect selected clip areas
|
||||
if (deselect_areas) {
|
||||
QVector<Selection> area_copy = areas;
|
||||
for (int i=0;i<area_copy.size();i++) {
|
||||
const Selection& s = area_copy.at(i);
|
||||
deselect_area(s.in, s.out, s.track);
|
||||
}
|
||||
}
|
||||
|
||||
relink_clips_using_ids(pre_clips, post_clips);
|
||||
ca->append(new AddClipCommand(olive::ActiveSequence.get(), post_clips));
|
||||
}
|
||||
|
||||
void Timeline::copy(bool del) {
|
||||
bool cleared = false;
|
||||
@@ -1220,23 +962,6 @@ void Timeline::copy(bool del) {
|
||||
}
|
||||
}
|
||||
|
||||
void Timeline::relink_clips_using_ids(QVector<int>& old_clips, QVector<ClipPtr>& new_clips) {
|
||||
// relink pasted clips
|
||||
for (int i=0;i<old_clips.size();i++) {
|
||||
// these indices should correspond
|
||||
ClipPtr oc = olive::ActiveSequence->clips.at(old_clips.at(i));
|
||||
for (int j=0;j<oc->linked.size();j++) {
|
||||
for (int k=0;k<old_clips.size();k++) { // find clip with that ID
|
||||
if (oc->linked.at(j) == old_clips.at(k)) {
|
||||
if (new_clips.at(i) != nullptr) {
|
||||
new_clips.at(i)->linked.append(k);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Timeline::paste(bool insert) {
|
||||
if (clipboard.size() > 0) {
|
||||
if (clipboard_type == CLIPBOARD_TYPE_CLIP) {
|
||||
@@ -1536,20 +1261,6 @@ bool Timeline::split_selection(ComboAction* ca) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Timeline::split_all_clips_at_point(ComboAction* ca, long point) {
|
||||
bool split = false;
|
||||
for (int j=0;j<olive::ActiveSequence->clips.size();j++) {
|
||||
ClipPtr c = olive::ActiveSequence->clips.at(j);
|
||||
if (c != nullptr) {
|
||||
// always relinks
|
||||
if (split_clip_and_relink(ca, j, point, true)) {
|
||||
split = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return split;
|
||||
}
|
||||
|
||||
void Timeline::split_at_playhead() {
|
||||
ComboAction* ca = new ComboAction();
|
||||
bool split_selected = false;
|
||||
@@ -1904,7 +1615,6 @@ void Timeline::transition_menu_select(QAction* a) {
|
||||
transition_tool_side = 1;
|
||||
}
|
||||
|
||||
decheck_tool_buttons(sender());
|
||||
timeline_area->setCursor(Qt::CrossCursor);
|
||||
tool = TIMELINE_TOOL_TRANSITION;
|
||||
toolTransitionButton->setChecked(true);
|
||||
@@ -2052,41 +1762,11 @@ void Timeline::setup_ui() {
|
||||
splitter->setChildrenCollapsible(false);
|
||||
splitter->setOrientation(Qt::Vertical);
|
||||
|
||||
QWidget* videoContainer = new QWidget();
|
||||
video_area = new TimelineArea();
|
||||
splitter->addWidget(video_area);
|
||||
|
||||
QHBoxLayout* videoContainerLayout = new QHBoxLayout(videoContainer);
|
||||
videoContainerLayout->setSpacing(0);
|
||||
videoContainerLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
video_area = new TimelineView();
|
||||
video_area->setFocusPolicy(Qt::ClickFocus);
|
||||
videoContainerLayout->addWidget(video_area);
|
||||
|
||||
videoScrollbar = new QScrollBar();
|
||||
videoScrollbar->setMaximum(0);
|
||||
videoScrollbar->setSingleStep(20);
|
||||
videoScrollbar->setOrientation(Qt::Vertical);
|
||||
videoContainerLayout->addWidget(videoScrollbar);
|
||||
|
||||
splitter->addWidget(videoContainer);
|
||||
|
||||
QWidget* audioContainer = new QWidget();
|
||||
QHBoxLayout* audioContainerLayout = new QHBoxLayout(audioContainer);
|
||||
audioContainerLayout->setSpacing(0);
|
||||
audioContainerLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
audio_area = new TimelineView();
|
||||
audio_area->setFocusPolicy(Qt::ClickFocus);
|
||||
|
||||
audioContainerLayout->addWidget(audio_area);
|
||||
|
||||
audioScrollbar = new QScrollBar();
|
||||
audioScrollbar->setMaximum(0);
|
||||
audioScrollbar->setOrientation(Qt::Vertical);
|
||||
|
||||
audioContainerLayout->addWidget(audioScrollbar);
|
||||
|
||||
splitter->addWidget(audioContainer);
|
||||
audio_area = new TimelineArea();
|
||||
splitter->addWidget(audio_area);
|
||||
|
||||
editAreaLayout->addWidget(splitter);
|
||||
|
||||
@@ -2111,7 +1791,6 @@ void Timeline::setup_ui() {
|
||||
|
||||
void Timeline::set_tool() {
|
||||
QPushButton* button = static_cast<QPushButton*>(sender());
|
||||
decheck_tool_buttons(button);
|
||||
tool = button->property("tool").toInt();
|
||||
creating = false;
|
||||
switch (tool) {
|
||||
|
||||
+3
-12
@@ -54,16 +54,9 @@ public:
|
||||
virtual bool focused() override;
|
||||
void multiply_zoom(double m);
|
||||
void copy(bool del);
|
||||
ClipPtr split_clip(ComboAction* ca, bool transitions, int p, long frame);
|
||||
ClipPtr split_clip(ComboAction* ca, bool transitions, int p, long frame, long post_in);
|
||||
bool split_selection(ComboAction* ca);
|
||||
bool split_all_clips_at_point(ComboAction *ca, long point);
|
||||
bool split_clip_and_relink(ComboAction* ca, int clip, long frame, bool relink);
|
||||
void split_clip_at_positions(ComboAction* ca, int clip_index, QVector<long> positions);
|
||||
void clean_up_selections(QVector<Selection>& areas);
|
||||
void deselect_area(long in, long out, int track);
|
||||
void delete_areas_and_relink(ComboAction *ca, QVector<Selection>& areas, bool deselect_areas);
|
||||
void relink_clips_using_ids(QVector<int>& old_clips, QVector<ClipPtr>& new_clips);
|
||||
void update_sequence();
|
||||
|
||||
void edit_to_point_internal(bool in, bool ripple);
|
||||
@@ -77,7 +70,7 @@ public:
|
||||
int getDisplayScreenPointFromFrame(long frame);
|
||||
long getDisplayFrameFromScreenPoint(int x);
|
||||
|
||||
int get_snap_range();
|
||||
long get_snap_range();
|
||||
bool snap_to_point(long point, long* l);
|
||||
bool snap_to_timeline(long* l, bool use_playhead, bool use_markers, bool use_workarea);
|
||||
void set_marker();
|
||||
@@ -152,6 +145,8 @@ public:
|
||||
AudioMonitor* audio_monitor;
|
||||
ResizableScrollBar* horizontalScrollBar;
|
||||
|
||||
QVector<QPushButton*> tool_buttons;
|
||||
QButtonGroup* tool_button_group;
|
||||
QPushButton* toolArrowButton;
|
||||
QPushButton* toolEditButton;
|
||||
QPushButton* toolRippleButton;
|
||||
@@ -216,8 +211,6 @@ private slots:
|
||||
private:
|
||||
void ChangeTrackHeightUniformly(int diff);
|
||||
void set_zoom_value(double v);
|
||||
QVector<QPushButton*> tool_buttons;
|
||||
void decheck_tool_buttons(QObject* sender);
|
||||
void set_tool(int tool);
|
||||
int scroll;
|
||||
void set_sb_max();
|
||||
@@ -233,8 +226,6 @@ private:
|
||||
TimelineArea* video_area;
|
||||
TimelineArea* audio_area;
|
||||
QWidget* editAreas;
|
||||
QScrollBar* videoScrollbar;
|
||||
QScrollBar* audioScrollbar;
|
||||
QPushButton* zoomInButton;
|
||||
QPushButton* zoomOutButton;
|
||||
QPushButton* recordButton;
|
||||
|
||||
+48
-4
@@ -348,13 +348,12 @@ void Viewer::pause() {
|
||||
|
||||
// Make a clip out of it and add it to the Sequence
|
||||
|
||||
ClipPtr c = std::make_shared<Clip>(seq.get());
|
||||
ClipPtr c = std::make_shared<Clip>(recording_track);
|
||||
|
||||
c->set_media(m, 0); // latest media
|
||||
c->set_timeline_in(recording_start);
|
||||
c->set_timeline_out(recording_start + f->get_length_in_frames(seq->frame_rate));
|
||||
c->set_clip_in(0);
|
||||
c->set_track(recording_track);
|
||||
c->set_color(128, 192, 128);
|
||||
c->set_name(m->get_name());
|
||||
|
||||
@@ -382,7 +381,7 @@ void Viewer::update_header_zoom() {
|
||||
if (seq != nullptr) {
|
||||
long sequenceEndFrame = seq->GetEndFrame();
|
||||
if (cached_end_frame != sequenceEndFrame) {
|
||||
minimum_zoom = (sequenceEndFrame > 0) ? ((double) headers->width() / (double) sequenceEndFrame) : 1;
|
||||
minimum_zoom = (sequenceEndFrame > 0) ? (double(headers->width()) / double(sequenceEndFrame)) : 1;
|
||||
headers->update_zoom(qMax(headers->get_zoom(), minimum_zoom));
|
||||
set_sb_max();
|
||||
viewer_widget_->waveform_zoom = headers->get_zoom();
|
||||
@@ -431,6 +430,51 @@ void Viewer::update_viewer() {
|
||||
update_end_timecode();
|
||||
}
|
||||
|
||||
void Viewer::prev_cut()
|
||||
{
|
||||
if (seq != nullptr
|
||||
&& seq->playhead > 0) {
|
||||
|
||||
QVector<Clip*> sequence_clips = olive::ActiveSequence->GetAllClips();
|
||||
|
||||
long p_cut = 0;
|
||||
for (int i=0;i<sequence_clips.size();i++) {
|
||||
Clip* c = sequence_clips.at(i);
|
||||
if (c->timeline_out() > p_cut && c->timeline_out() < seq->playhead) {
|
||||
p_cut = c->timeline_out();
|
||||
} else if (c->timeline_in() > p_cut && c->timeline_in() < seq->playhead) {
|
||||
p_cut = c->timeline_in();
|
||||
}
|
||||
}
|
||||
panel_sequence_viewer->seek(p_cut);
|
||||
}
|
||||
}
|
||||
|
||||
void Viewer::next_cut()
|
||||
{
|
||||
if (seq != nullptr) {
|
||||
|
||||
QVector<Clip*> sequence_clips = seq->GetAllClips();
|
||||
|
||||
bool seek_enabled = false;
|
||||
long n_cut = LONG_MAX;
|
||||
for (int i=0;i<sequence_clips.size();i++) {
|
||||
Clip* c = sequence_clips.at(i);
|
||||
if (c->timeline_in() < n_cut && c->timeline_in() > seq->playhead) {
|
||||
n_cut = c->timeline_in();
|
||||
seek_enabled = true;
|
||||
} else if (c->timeline_out() < n_cut && c->timeline_out() > seq->playhead) {
|
||||
n_cut = c->timeline_out();
|
||||
seek_enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (seek_enabled) {
|
||||
panel_sequence_viewer->seek(n_cut);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Viewer::initiate_drag(olive::timeline::MediaImportType drag_type)
|
||||
{
|
||||
// FIXME: This should contain actual metadata rather than fake metadata
|
||||
@@ -703,7 +747,7 @@ void Viewer::set_media(Media* m) {
|
||||
new_sequence->frame_rate = video_stream.video_frame_rate * footage->speed;
|
||||
}
|
||||
|
||||
ClipPtr c = std::make_shared<Clip>(new_sequence.get());
|
||||
ClipPtr c = std::make_shared<Clip>(new_sequence->GetTrackList(Track::kTypeVideo)->First());
|
||||
c->set_media(media, video_stream.file_index);
|
||||
c->set_timeline_in(0);
|
||||
c->set_timeline_out(footage->get_length_in_frames(new_sequence->frame_rate));
|
||||
|
||||
+2
-1
@@ -115,7 +115,8 @@ public slots:
|
||||
void go_to_end();
|
||||
void close_media();
|
||||
void update_viewer();
|
||||
|
||||
void prev_cut();
|
||||
void next_cut();
|
||||
|
||||
|
||||
private slots:
|
||||
|
||||
+7
-8
@@ -54,7 +54,7 @@ void Footage::Save(QXmlStreamWriter &stream)
|
||||
QDir proj_dir = QFileInfo(olive::ActiveProjectFilename).absoluteDir();
|
||||
|
||||
stream.writeStartElement("footage");
|
||||
stream.writeAttribute("id", QString::number(media_id));
|
||||
stream.writeAttribute("id", QString::number(save_id));
|
||||
stream.writeAttribute("name", name);
|
||||
stream.writeAttribute("url", proj_dir.relativeFilePath(url));
|
||||
stream.writeAttribute("duration", QString::number(length));
|
||||
@@ -70,8 +70,8 @@ void Footage::Save(QXmlStreamWriter &stream)
|
||||
stream.writeAttribute("proxypath", proxy_path);
|
||||
|
||||
// save video stream metadata
|
||||
for (int j=0;j<f->video_tracks.size();j++) {
|
||||
const FootageStream& ms = f->video_tracks.at(j);
|
||||
for (int j=0;j<video_tracks.size();j++) {
|
||||
const FootageStream& ms = video_tracks.at(j);
|
||||
stream.writeStartElement("video");
|
||||
stream.writeAttribute("id", QString::number(ms.file_index));
|
||||
stream.writeAttribute("width", QString::number(ms.video_width));
|
||||
@@ -82,8 +82,8 @@ void Footage::Save(QXmlStreamWriter &stream)
|
||||
}
|
||||
|
||||
// save audio stream metadata
|
||||
for (int j=0;j<f->audio_tracks.size();j++) {
|
||||
const FootageStream& ms = f->audio_tracks.at(j);
|
||||
for (int j=0;j<audio_tracks.size();j++) {
|
||||
const FootageStream& ms = audio_tracks.at(j);
|
||||
stream.writeStartElement("audio");
|
||||
stream.writeAttribute("id", QString::number(ms.file_index));
|
||||
stream.writeAttribute("channels", QString::number(ms.audio_channels));
|
||||
@@ -93,12 +93,11 @@ void Footage::Save(QXmlStreamWriter &stream)
|
||||
}
|
||||
|
||||
// save footage markers
|
||||
for (int j=0;j<f->markers.size();j++) {
|
||||
f->markers.at(j).Save(stream);
|
||||
for (int j=0;j<markers.size();j++) {
|
||||
markers.at(j).Save(stream);
|
||||
}
|
||||
|
||||
stream.writeEndElement(); // footage
|
||||
media_id++;
|
||||
}
|
||||
|
||||
QString Footage::Colorspace()
|
||||
|
||||
+16
-18
@@ -64,7 +64,6 @@ ClipPtr Clip::copy(Track* s) {
|
||||
copy->set_clip_in(clip_in());
|
||||
copy->set_timeline_in(timeline_in());
|
||||
copy->set_timeline_out(timeline_out());
|
||||
copy->set_track(track());
|
||||
copy->set_color(color());
|
||||
copy->set_media(media(), media_stream_index());
|
||||
copy->set_autoscaled(autoscaled());
|
||||
@@ -75,7 +74,7 @@ ClipPtr Clip::copy(Track* s) {
|
||||
copy->effects.append(effects.at(i)->copy(copy.get()));
|
||||
}
|
||||
|
||||
copy->set_cached_frame_rate((this->track_ == nullptr) ? cached_frame_rate() : this->track_->frame_rate);
|
||||
copy->set_cached_frame_rate((this->track_ == nullptr) ? cached_frame_rate() : this->track_->sequence()->frame_rate);
|
||||
|
||||
copy->refresh();
|
||||
|
||||
@@ -207,13 +206,13 @@ void Clip::reset_audio() {
|
||||
cacher.ResetAudio();
|
||||
}
|
||||
if (media() != nullptr && media()->get_type() == MEDIA_TYPE_SEQUENCE) {
|
||||
Sequence* nested_sequence = media()->to_sequence().get();
|
||||
for (int i=0;i<nested_sequence->clips.size();i++) {
|
||||
Clip* c = nested_sequence->clips.at(i).get();
|
||||
if (c != nullptr) {
|
||||
c->reset_audio();
|
||||
}
|
||||
|
||||
QVector<Clip*> nested_sequence_clips = media()->to_sequence()->GetAllClips();
|
||||
|
||||
for (int i=0;i<nested_sequence_clips.size();i++) {
|
||||
nested_sequence_clips.at(i)->reset_audio();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -266,7 +265,6 @@ void Clip::Save(QXmlStreamWriter &stream)
|
||||
stream.writeAttribute("clipin", QString::number(clip_in()));
|
||||
stream.writeAttribute("in", QString::number(timeline_in()));
|
||||
stream.writeAttribute("out", QString::number(timeline_out()));
|
||||
stream.writeAttribute("track", QString::number(track()));
|
||||
|
||||
stream.writeAttribute("r", QString::number(color().red()));
|
||||
stream.writeAttribute("g", QString::number(color().green()));
|
||||
@@ -277,9 +275,9 @@ void Clip::Save(QXmlStreamWriter &stream)
|
||||
stream.writeAttribute("maintainpitch", QString::number(speed().maintain_audio_pitch));
|
||||
stream.writeAttribute("reverse", QString::number(reversed()));
|
||||
|
||||
if (c->media() != nullptr) {
|
||||
if (media() != nullptr) {
|
||||
stream.writeAttribute("type", QString::number(media()->get_type()));
|
||||
switch (c->media()->get_type()) {
|
||||
switch (media()->get_type()) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
stream.writeAttribute("media", QString::number(media()->to_footage()->save_id));
|
||||
stream.writeAttribute("stream", QString::number(media_stream_index()));
|
||||
@@ -302,7 +300,7 @@ void Clip::Save(QXmlStreamWriter &stream)
|
||||
stream.writeStartElement("linked"); // linked
|
||||
for (int k=0;k<linked.size();k++) {
|
||||
stream.writeStartElement("link"); // link
|
||||
stream.writeAttribute("id", QString::number(linked.at(k)));
|
||||
stream.writeAttribute("id", QString::number(linked.at(k)->load_id));
|
||||
stream.writeEndElement(); // link
|
||||
}
|
||||
stream.writeEndElement(); // linked
|
||||
@@ -457,13 +455,13 @@ double Clip::media_frame_rate() {
|
||||
double rate = media_->get_frame_rate(media_stream_index());
|
||||
if (!qIsNaN(rate)) return rate;
|
||||
}
|
||||
if (sequence != nullptr) return sequence->frame_rate;
|
||||
if (track() != nullptr) return track()->sequence()->frame_rate;
|
||||
return qSNaN();
|
||||
}
|
||||
|
||||
long Clip::media_length() {
|
||||
if (this->sequence != nullptr) {
|
||||
double fr = this->sequence->frame_rate;
|
||||
if (this->track() != nullptr) {
|
||||
double fr = this->track()->sequence()->frame_rate;
|
||||
|
||||
fr /= speed_.value;
|
||||
|
||||
@@ -474,7 +472,7 @@ long Clip::media_length() {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
Footage* m = media_->to_footage();
|
||||
const FootageStream* ms = m->get_stream_from_file_index(track_ < 0, media_stream_index());
|
||||
const FootageStream* ms = m->get_stream_from_file_index(type() == Track::kTypeVideo, media_stream_index());
|
||||
if (ms != nullptr && ms->infinite_length) {
|
||||
return LONG_MAX;
|
||||
} else {
|
||||
@@ -493,13 +491,13 @@ long Clip::media_length() {
|
||||
}
|
||||
|
||||
int Clip::media_width() {
|
||||
if (media_ == nullptr && sequence != nullptr) return sequence->width;
|
||||
if (media_ == nullptr && track() != nullptr) return track()->sequence()->width;
|
||||
switch (media_->get_type()) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
{
|
||||
const FootageStream* ms = media_stream();
|
||||
if (ms != nullptr) return ms->video_width;
|
||||
if (sequence != nullptr) return sequence->width;
|
||||
if (track() != nullptr) return track()->sequence()->width;
|
||||
break;
|
||||
}
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
|
||||
+3
-2
@@ -3,17 +3,18 @@
|
||||
|
||||
#include "effects/transition.h"
|
||||
#include "timelinefunctions.h"
|
||||
#include "track.h"
|
||||
|
||||
struct Ghost {
|
||||
int clip;
|
||||
long in;
|
||||
long out;
|
||||
int track;
|
||||
Track* track;
|
||||
long clip_in;
|
||||
|
||||
long old_in;
|
||||
long old_out;
|
||||
int old_track;
|
||||
Track* old_track;
|
||||
long old_clip_in;
|
||||
|
||||
// importing variables
|
||||
|
||||
+265
-24
@@ -33,10 +33,10 @@ Sequence::Sequence() :
|
||||
wrapper_sequence(false)
|
||||
{
|
||||
// Set up tracks
|
||||
track_lists.resize(Track::kTypeCount);
|
||||
track_lists_.resize(Track::kTypeCount);
|
||||
|
||||
for (int i=0;i<track_lists.size();i++) {
|
||||
track_lists[i] = std::make_shared<TrackList>(this, i);
|
||||
for (int i=0;i<track_lists_.size();i++) {
|
||||
track_lists_[i] = new TrackList(this, static_cast<Track::Type>(i));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,8 +50,8 @@ SequencePtr Sequence::copy() {
|
||||
s->audio_layout = audio_layout;
|
||||
|
||||
// deep copy all of the sequence's clips
|
||||
for (int i=0;i<track_lists.size();i++) {
|
||||
s->track_lists[i] = track_lists.at(i).copy(s.get());
|
||||
for (int i=0;i<track_lists_.size();i++) {
|
||||
s->track_lists_[i] = track_lists_.at(i)->copy(s.get());
|
||||
}
|
||||
|
||||
// copy all of the sequence's markers
|
||||
@@ -62,6 +62,12 @@ SequencePtr Sequence::copy() {
|
||||
|
||||
void Sequence::Save(QXmlStreamWriter &stream)
|
||||
{
|
||||
// Provide unique IDs for each Clip
|
||||
QVector<Clip*> all_clips = GetAllClips();
|
||||
for (int i=0;i<all_clips.size();i++) {
|
||||
all_clips.at(i)->load_id = i;
|
||||
}
|
||||
|
||||
stream.writeStartElement("sequence");
|
||||
stream.writeAttribute("id", QString::number(save_id));
|
||||
stream.writeAttribute("name", name);
|
||||
@@ -80,22 +86,28 @@ void Sequence::Save(QXmlStreamWriter &stream)
|
||||
QVector<TransitionPtr> transition_save_cache;
|
||||
QVector<int> transition_clip_save_cache;
|
||||
|
||||
for (int j=0;j<tracks.size();j++) {
|
||||
tracks.at(j)->Save(stream);
|
||||
for (int j=0;j<track_lists_.size();j++) {
|
||||
track_lists_.at(j)->Save(stream);
|
||||
}
|
||||
|
||||
|
||||
for (int j=0;j<markers.size();j++) {
|
||||
markers.at(j).Save(stream);
|
||||
}
|
||||
|
||||
stream.writeEndElement();
|
||||
}
|
||||
|
||||
long Sequence::GetEndFrame() {
|
||||
long end_frame = 0;
|
||||
|
||||
for (int i=0;i<tracks.size();i++) {
|
||||
end_frame = qMax(tracks.at(i)->GetEndFrame(), end_frame);
|
||||
for (int j=0;j<track_lists_.size();j++) {
|
||||
|
||||
TrackList* track_list = track_lists_.at(j);
|
||||
|
||||
for (int i=0;i<track_list->TrackCount();i++) {
|
||||
end_frame = qMax(track_list->TrackAt(i)->GetEndFrame(), end_frame);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return end_frame;
|
||||
@@ -105,8 +117,14 @@ QVector<Clip *> Sequence::GetAllClips()
|
||||
{
|
||||
QVector<Clip*> all_clips;
|
||||
|
||||
for (int i=0;i<tracks.size();i++) {
|
||||
all_clips.append(tracks.at(i)->GetAllClips());
|
||||
for (int j=0;j<track_lists_.size();j++) {
|
||||
|
||||
TrackList* track_list = track_lists_.at(j);
|
||||
|
||||
for (int i=0;i<track_list->TrackCount();i++) {
|
||||
all_clips.append(track_list->TrackAt(i)->GetAllClips());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return all_clips;
|
||||
@@ -114,7 +132,7 @@ QVector<Clip *> Sequence::GetAllClips()
|
||||
|
||||
TrackList *Sequence::GetTrackList(Track::Type type)
|
||||
{
|
||||
return track_lists.at(type).get();
|
||||
return track_lists_.at(type);
|
||||
}
|
||||
|
||||
void Sequence::Close()
|
||||
@@ -143,20 +161,158 @@ void Sequence::RefreshClipsUsingMedia(Media *m) {
|
||||
|
||||
QVector<Clip *> Sequence::SelectedClips(bool containing)
|
||||
{
|
||||
QVector<Clip*> all_clips = GetAllClips();
|
||||
|
||||
QVector<Clip*> selected_clips;
|
||||
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
Clip* c = clips.at(i).get();
|
||||
if (c != nullptr && IsClipSelected(c, containing)) {
|
||||
selected_clips.append(c);
|
||||
for (int i=0;i<track_lists_.size();i++) {
|
||||
TrackList* tl = track_lists_.at(i);
|
||||
|
||||
for (int j=0;j<tl->TrackCount();j++) {
|
||||
Track* t = tl->TrackAt(j);
|
||||
|
||||
selected_clips.append(t->GetAllClips());
|
||||
}
|
||||
}
|
||||
|
||||
return selected_clips;
|
||||
}
|
||||
|
||||
void Sequence::DeleteAreas(ComboAction* ca, QVector<Selection>& areas, bool deselect_areas)
|
||||
{
|
||||
clean_up_selections(areas);
|
||||
|
||||
panel_graph_editor->set_row(nullptr);
|
||||
panel_effect_controls->Clear(true);
|
||||
|
||||
QVector<int> pre_clips;
|
||||
QVector<ClipPtr> post_clips;
|
||||
|
||||
QVector<Clip*> all_clips = GetAllClips();
|
||||
|
||||
for (int i=0;i<areas.size();i++) {
|
||||
const Selection& s = areas.at(i);
|
||||
for (int j=0;j<all_clips.size();j++) {
|
||||
Clip* c = all_clips.at(j);
|
||||
if (c != nullptr && c->track() == s.track && !c->undeletable) {
|
||||
if (selection_contains_transition(s, c, kTransitionOpening)) {
|
||||
// delete opening transition
|
||||
ca->append(new DeleteTransitionCommand(c->opening_transition));
|
||||
} else if (selection_contains_transition(s, c, kTransitionClosing)) {
|
||||
// delete closing transition
|
||||
ca->append(new DeleteTransitionCommand(c->closing_transition));
|
||||
} else if (c->timeline_in() >= s.in && c->timeline_out() <= s.out) {
|
||||
// clips falls entirely within deletion area
|
||||
ca->append(new DeleteClipAction(c));
|
||||
} else if (c->timeline_in() < s.in && c->timeline_out() > s.out) {
|
||||
// middle of clip is within deletion area
|
||||
|
||||
// duplicate clip
|
||||
ClipPtr post = SplitClip(ca, true, c, s.in, s.out);
|
||||
|
||||
pre_clips.append(j);
|
||||
post_clips.append(post);
|
||||
} else if (c->timeline_in() < s.in && c->timeline_out() > s.in) {
|
||||
// only out point is in deletion area
|
||||
c->move(ca, c->timeline_in(), s.in, c->clip_in(), c->track());
|
||||
|
||||
if (c->closing_transition != nullptr) {
|
||||
if (s.in < c->timeline_out() - c->closing_transition->get_true_length()) {
|
||||
ca->append(new DeleteTransitionCommand(c->closing_transition));
|
||||
} else {
|
||||
ca->append(new ModifyTransitionCommand(c->closing_transition, c->closing_transition->get_true_length() - (c->timeline_out() - s.in)));
|
||||
}
|
||||
}
|
||||
} else if (c->timeline_in() < s.out && c->timeline_out() > s.out) {
|
||||
// only in point is in deletion area
|
||||
c->move(ca, s.out, c->timeline_out(), c->clip_in() + (s.out - c->timeline_in()), c->track());
|
||||
|
||||
if (c->opening_transition != nullptr) {
|
||||
if (s.out > c->timeline_in() + c->opening_transition->get_true_length()) {
|
||||
ca->append(new DeleteTransitionCommand(c->opening_transition));
|
||||
} else {
|
||||
ca->append(new ModifyTransitionCommand(c->opening_transition, c->opening_transition->get_true_length() - (s.out - c->timeline_in())));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// deselect selected clip areas
|
||||
if (deselect_areas) {
|
||||
QVector<Selection> area_copy = areas;
|
||||
for (int i=0;i<area_copy.size();i++) {
|
||||
const Selection& s = area_copy.at(i);
|
||||
deselect_area(s.in, s.out, s.track);
|
||||
}
|
||||
}
|
||||
|
||||
relink_clips_using_ids(pre_clips, post_clips);
|
||||
ca->append(new AddClipCommand(olive::ActiveSequence.get(), post_clips));
|
||||
}
|
||||
|
||||
bool Sequence::SplitAllClipsAtPoint(ComboAction *ca, long point)
|
||||
{
|
||||
bool split = false;
|
||||
|
||||
QVector<Clip*> all_clips = GetAllClips();
|
||||
|
||||
for (int j=0;j<all_clips.size();j++) {
|
||||
Clip* c = all_clips.at(j);
|
||||
|
||||
if (c->IsActiveAt(point)) {
|
||||
SplitClipAtPositions(ca, c, {point}, true);
|
||||
split = true;
|
||||
}
|
||||
}
|
||||
|
||||
return split;
|
||||
}
|
||||
|
||||
void Sequence::SplitClipAtPositions(ComboAction *ca, Clip* clip, QVector<long> positions, bool relink)
|
||||
{
|
||||
// Add the clip and each of its links to the pre_splits array
|
||||
|
||||
QVector<Clip*> pre_splits;
|
||||
pre_splits.append(clip);
|
||||
|
||||
if (relink) {
|
||||
for (int i=0;i<clip->linked.size();i++) {
|
||||
pre_splits.append(clip->linked.at(i));
|
||||
}
|
||||
}
|
||||
|
||||
std::sort(positions.begin(), positions.end());
|
||||
|
||||
// Remove any duplicate positions
|
||||
for (int i=1;i<positions.size();i++) {
|
||||
if (positions.at(i-1) == positions.at(i)) {
|
||||
positions.removeAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
QVector< QVector<ClipPtr> > post_splits(positions.size());
|
||||
|
||||
for (int i=positions.size()-1;i>=0;i--) {
|
||||
|
||||
post_splits[i].resize(pre_splits.size());
|
||||
|
||||
for (int j=0;j<pre_splits.size();j++) {
|
||||
post_splits[i][j] = SplitClip(ca, true, pre_splits.at(j), positions.at(i));
|
||||
|
||||
if (post_splits[i][j] != nullptr && i + 1 < positions.size()) {
|
||||
post_splits[i][j]->set_timeline_out(positions.at(i+1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i=0;i<post_splits.size();i++) {
|
||||
olive::timeline::RelinkClips(pre_splits, post_splits[i]);
|
||||
ca->append(new AddClipCommand(olive::ActiveSequence.get(), post_splits[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
QVector<int> Sequence::SelectedClipIndexes()
|
||||
{
|
||||
QVector<int> selected_clips;
|
||||
@@ -170,15 +326,17 @@ QVector<int> Sequence::SelectedClipIndexes()
|
||||
|
||||
return selected_clips;
|
||||
}
|
||||
*/
|
||||
|
||||
Effect *Sequence::GetSelectedGizmo()
|
||||
{
|
||||
Effect* gizmo_ptr = nullptr;
|
||||
|
||||
QVector<Clip*> clips = GetAllClips();
|
||||
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
Clip* c = clips.at(i).get();
|
||||
if (c != nullptr
|
||||
&& c->IsActiveAt(playhead)
|
||||
Clip* c = clips.at(i);
|
||||
if (c->IsActiveAt(playhead)
|
||||
&& IsClipSelected(c, true)) {
|
||||
// This clip is selected and currently active - we'll use this for gizmos
|
||||
|
||||
@@ -214,10 +372,93 @@ Effect *Sequence::GetSelectedGizmo()
|
||||
|
||||
void Sequence::ClearSelections()
|
||||
{
|
||||
for (int i=0;i<tracks.size();i++) {
|
||||
tracks.at(i)->ClearSelections();
|
||||
for (int j=0;j<track_lists_.size();j++) {
|
||||
TrackList* tl = track_lists_.at(j);
|
||||
|
||||
for (int i=0;i<tl->TrackCount();i++) {
|
||||
tl->TrackAt(i)->ClearSelections();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ClipPtr Sequence::SplitClip(ComboAction *ca, bool transitions, Clip* pre, long frame)
|
||||
{
|
||||
return SplitClip(ca, transitions, pre, frame, frame);
|
||||
}
|
||||
|
||||
ClipPtr Sequence::SplitClip(ComboAction *ca, bool transitions, Clip* pre, long frame, long post_in)
|
||||
{
|
||||
if (pre == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (pre->timeline_in() < frame && pre->timeline_out() > frame) {
|
||||
// duplicate clip without duplicating its transitions, we'll restore them later
|
||||
|
||||
ClipPtr post = pre->copy(pre->track());
|
||||
|
||||
long new_clip_length = frame - pre->timeline_in();
|
||||
|
||||
post->set_timeline_in(post_in);
|
||||
post->set_clip_in(pre->clip_in() + (post->timeline_in() - pre->timeline_in()));
|
||||
|
||||
pre->move(ca, pre->timeline_in(), frame, pre->clip_in(), pre->track(), false);
|
||||
|
||||
if (transitions) {
|
||||
|
||||
// check if this clip has a closing transition
|
||||
if (pre->closing_transition != nullptr) {
|
||||
|
||||
// if so, move closing transition to the post clip
|
||||
post->closing_transition = pre->closing_transition;
|
||||
|
||||
// and set the original clip's closing transition to nothing
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&pre->closing_transition), nullptr));
|
||||
|
||||
// and set the transition's reference to the post clip
|
||||
if (post->closing_transition->parent_clip == pre) {
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&post->closing_transition->parent_clip), post.get()));
|
||||
}
|
||||
if (post->closing_transition->secondary_clip == pre) {
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&post->closing_transition->secondary_clip), post.get()));
|
||||
}
|
||||
|
||||
// and make sure it's at the correct size to the closing clip
|
||||
if (post->closing_transition != nullptr && post->closing_transition->get_true_length() > post->length()) {
|
||||
ca->append(new ModifyTransitionCommand(post->closing_transition, post->length()));
|
||||
post->closing_transition->set_length(post->length());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// we're keeping the opening clip, so ensure that's a correct size too
|
||||
if (pre->opening_transition != nullptr && pre->opening_transition->get_true_length() > new_clip_length) {
|
||||
ca->append(new ModifyTransitionCommand(pre->opening_transition, new_clip_length));
|
||||
}
|
||||
}
|
||||
|
||||
return post;
|
||||
|
||||
} else if (frame == pre->timeline_in()
|
||||
&& pre->opening_transition != nullptr
|
||||
&& pre->opening_transition->secondary_clip != nullptr) {
|
||||
// special case for shared transitions to split it into two
|
||||
|
||||
// set transition to single-clip mode
|
||||
ca->append(new SetPointer(reinterpret_cast<void**>(&pre->opening_transition->secondary_clip), nullptr));
|
||||
|
||||
// clone transition for other clip
|
||||
ca->append(new AddTransitionCommand(nullptr,
|
||||
pre->opening_transition->secondary_clip,
|
||||
pre->opening_transition,
|
||||
nullptr,
|
||||
0)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// static variable for the currently active sequence
|
||||
SequencePtr olive::ActiveSequence = nullptr;
|
||||
|
||||
+10
-2
@@ -63,7 +63,12 @@ public:
|
||||
|
||||
void RefreshClipsUsingMedia(Media* m = nullptr);
|
||||
QVector<Clip*> SelectedClips(bool containing = true);
|
||||
QVector<int> SelectedClipIndexes();
|
||||
//QVector<int> SelectedClipIndexes();
|
||||
|
||||
void DeleteAreas();
|
||||
|
||||
bool SplitAllClipsAtPoint(ComboAction *ca, long point);
|
||||
void SplitClipAtPositions(ComboAction* ca, Clip *clip, QVector<long> positions, bool relink = true);
|
||||
|
||||
Effect* GetSelectedGizmo();
|
||||
|
||||
@@ -84,7 +89,10 @@ public:
|
||||
|
||||
QVector<Marker> markers;
|
||||
private:
|
||||
QVector<TrackList*> track_lists;
|
||||
QVector<TrackList*> track_lists_;
|
||||
|
||||
ClipPtr SplitClip(ComboAction* ca, bool transitions, Clip *clip, long frame);
|
||||
ClipPtr SplitClip(ComboAction* ca, bool transitions, Clip *clip, long frame, long post_in);
|
||||
};
|
||||
|
||||
using SequencePtr = std::shared_ptr<Sequence>;
|
||||
|
||||
@@ -1,6 +1,30 @@
|
||||
#include "timelinefunctions.h"
|
||||
|
||||
TimelineFunctions::TimelineFunctions()
|
||||
{
|
||||
|
||||
|
||||
void olive::timeline::RelinkClips(QVector<Clip *> &pre_clips, QVector<ClipPtr> &post_clips)
|
||||
{
|
||||
// Loop through each "pre" clip
|
||||
for (int i=0;i<pre_clips.size();i++) {
|
||||
|
||||
Clip* pre = pre_clips.at(i);
|
||||
|
||||
// Loop through each "pre" clip's linked array
|
||||
for (int j=0;j<pre->linked.size();j++) {
|
||||
|
||||
// Loop again through the "pre" clips to determine which are linked to each other
|
||||
for (int l=0;l<pre_clips.size();l++) {
|
||||
|
||||
// If this "pre" is linked to this "pre"
|
||||
if (pre->linked.at(j) == pre_clips.at(l)) {
|
||||
|
||||
// Check if we have an equivalent in the post_clips, and link it if so
|
||||
if (post_clips.at(l) != nullptr) {
|
||||
post_clips.at(i)->linked.append(post_clips.at(l).get());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
#ifndef TIMELINEFUNCTIONS_H
|
||||
#define TIMELINEFUNCTIONS_H
|
||||
|
||||
#include <QVector>
|
||||
|
||||
#include "timeline/clip.h"
|
||||
|
||||
namespace olive {
|
||||
namespace timeline {
|
||||
|
||||
@@ -25,13 +29,9 @@ enum Alignment {
|
||||
kAlignmentSingle
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
void RelinkClips(QVector<Clip*>& pre_clips, QVector<ClipPtr> &post_clips);
|
||||
|
||||
class TimelineFunctions
|
||||
{
|
||||
public:
|
||||
TimelineFunctions();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TIMELINEFUNCTIONS_H
|
||||
|
||||
+90
-8
@@ -1,6 +1,8 @@
|
||||
#include "track.h"
|
||||
|
||||
#include "timeline/clip.h"
|
||||
#include "timeline/tracklist.h"
|
||||
#include "timeline/sequence.h"
|
||||
|
||||
int olive::timeline::kTrackDefaultHeight = 40;
|
||||
int olive::timeline::kTrackMinHeight = 30;
|
||||
@@ -30,20 +32,29 @@ Track *Track::copy(TrackList *parent)
|
||||
return t;
|
||||
}
|
||||
|
||||
Sequence *Track::sequence()
|
||||
{
|
||||
return parent_->GetParent();
|
||||
}
|
||||
|
||||
TrackList *Track::track_list()
|
||||
{
|
||||
return parent_;
|
||||
}
|
||||
|
||||
void Track::Save(QXmlStreamWriter &stream)
|
||||
{
|
||||
stream.writeStartElement("track");
|
||||
|
||||
for (int j=0;j<clips_.size();j++) {
|
||||
Clip* c = clips_.at(j).get();
|
||||
if (c != nullptr) {
|
||||
stream.writeStartElement("clip");
|
||||
stream.writeAttribute("id", QString::number(j));
|
||||
|
||||
c->Save(stream);
|
||||
stream.writeStartElement("clip");
|
||||
stream.writeAttribute("id", QString::number(c->load_id));
|
||||
|
||||
stream.writeEndElement(); // clip
|
||||
}
|
||||
c->Save(stream);
|
||||
|
||||
stream.writeEndElement(); // clip
|
||||
}
|
||||
|
||||
stream.writeEndElement(); // track
|
||||
@@ -93,9 +104,49 @@ void Track::ResizeClipArray(int new_size)
|
||||
clips_.resize(new_size);
|
||||
}
|
||||
|
||||
QVector<ClipPtr> Track::GetAllClips()
|
||||
QVector<Clip*> Track::GetAllClips()
|
||||
{
|
||||
return clips_;
|
||||
QVector<Clip*> clips;
|
||||
|
||||
clips.resize(clips_.size());
|
||||
for (int i=0;i<clips_.size();i++) {
|
||||
clips[i] = clips_.at(i).get();
|
||||
}
|
||||
|
||||
return clips;
|
||||
}
|
||||
|
||||
QVector<Clip *> Track::GetSelectedClips(bool containing)
|
||||
{
|
||||
QVector<Clip*> selected_clips;
|
||||
|
||||
for (int i=0;i<clips_.size();i++) {
|
||||
|
||||
Clip* c = clips_.at(i).get();
|
||||
|
||||
if (IsClipSelected(c, containing)) {
|
||||
selected_clips.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
return selected_clips;
|
||||
}
|
||||
|
||||
ClipPtr Track::GetClipObjectFromRawPtr(Clip *c)
|
||||
{
|
||||
for (int i=0;i<clips_.size();i++) {
|
||||
if (clips_.at(i).get() == c) {
|
||||
return clips_.at(i);
|
||||
}
|
||||
}
|
||||
|
||||
// Assert here since we shouldn't be calling this function ever
|
||||
Q_ASSERT(false);
|
||||
}
|
||||
|
||||
int Track::Index()
|
||||
{
|
||||
return parent_->IndexOfTrack(this);
|
||||
}
|
||||
|
||||
bool Track::IsClipSelected(int clip_index, bool containing)
|
||||
@@ -157,6 +208,37 @@ bool Track::IsTransitionSelected(Transition *t)
|
||||
return false;
|
||||
}
|
||||
|
||||
void Track::TidySelections()
|
||||
{
|
||||
for (int i=0;i<areas.size();i++) {
|
||||
Selection& s = areas[i];
|
||||
for (int j=0;j<areas.size();j++) {
|
||||
if (i != j) {
|
||||
Selection& ss = areas[j];
|
||||
if (s.track == ss.track) {
|
||||
bool remove = false;
|
||||
if (s.in < ss.in && s.out > ss.out) {
|
||||
// do nothing
|
||||
} else if (s.in >= ss.in && s.out <= ss.out) {
|
||||
remove = true;
|
||||
} else if (s.in <= ss.out && s.out > ss.out) {
|
||||
ss.out = s.out;
|
||||
remove = true;
|
||||
} else if (s.out >= ss.in && s.in < ss.in) {
|
||||
ss.in = s.in;
|
||||
remove = true;
|
||||
}
|
||||
if (remove) {
|
||||
areas.removeAt(i);
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Track::ClearSelections()
|
||||
{
|
||||
selections_.clear();
|
||||
|
||||
+9
-2
@@ -43,6 +43,9 @@ public:
|
||||
Track(TrackList* parent, Type type);
|
||||
Track* copy(TrackList* parent);
|
||||
|
||||
Sequence* sequence();
|
||||
TrackList* track_list();
|
||||
|
||||
void Save(QXmlStreamWriter& stream);
|
||||
|
||||
Type type();
|
||||
@@ -55,13 +58,17 @@ public:
|
||||
ClipPtr GetClip(int i);
|
||||
void RemoveClip(int i);
|
||||
void RemoveClip(Clip* c);
|
||||
QVector<ClipPtr> GetAllClips();
|
||||
QVector<Clip*> GetSelectedClips();
|
||||
QVector<Clip*> GetAllClips();
|
||||
QVector<Clip*> GetSelectedClips(bool containing);
|
||||
ClipPtr GetClipObjectFromRawPtr(Clip* c);
|
||||
|
||||
int Index();
|
||||
|
||||
bool IsClipSelected(int clip_index, bool containing = true);
|
||||
bool IsClipSelected(Clip* clip, bool containing = true);
|
||||
bool IsTransitionSelected(Transition* t);
|
||||
|
||||
void TidySelections();
|
||||
void ClearSelections();
|
||||
|
||||
long GetEndFrame();
|
||||
|
||||
+39
-6
@@ -1,5 +1,7 @@
|
||||
#include "tracklist.h"
|
||||
|
||||
#include "timeline/sequence.h"
|
||||
|
||||
TrackList::TrackList(Sequence *parent, Track::Type type) :
|
||||
QObject(parent),
|
||||
type_(type)
|
||||
@@ -8,13 +10,24 @@ TrackList::TrackList(Sequence *parent, Track::Type type) :
|
||||
AddTrack();
|
||||
}
|
||||
|
||||
TrackListPtr TrackList::copy(Sequence *parent)
|
||||
void TrackList::Save(QXmlStreamWriter &stream)
|
||||
{
|
||||
TrackListPtr t = std::make_shared<TrackList>(parent, type_);
|
||||
stream.writeStartElement("Tracks");
|
||||
|
||||
for (int i=0;i<tracks_.size();i++) {
|
||||
tracks_.at(i)->Save(stream);
|
||||
}
|
||||
|
||||
stream.writeEndElement(); // Tracks
|
||||
}
|
||||
|
||||
TrackList* TrackList::copy(Sequence *parent)
|
||||
{
|
||||
TrackList* t = new TrackList(parent, type_);
|
||||
|
||||
t->ResizeTrackArray(tracks_.size());
|
||||
for (int i=0;i<tracks_.size();i++) {
|
||||
t->tracks_[i] = tracks_.at(i)->copy(t.get());
|
||||
t->tracks_[i] = tracks_.at(i)->copy(t);
|
||||
}
|
||||
|
||||
return t;
|
||||
@@ -22,7 +35,7 @@ TrackListPtr TrackList::copy(Sequence *parent)
|
||||
|
||||
void TrackList::AddTrack()
|
||||
{
|
||||
TrackPtr track = std::make_shared<Track>(this, type_);
|
||||
Track* track = new Track(this, type_);
|
||||
tracks_.append(track);
|
||||
}
|
||||
|
||||
@@ -36,7 +49,7 @@ void TrackList::RemoveTrack(int i)
|
||||
|
||||
Track *TrackList::First()
|
||||
{
|
||||
return tracks_.first().get();
|
||||
return tracks_.first();
|
||||
}
|
||||
|
||||
int TrackList::TrackCount()
|
||||
@@ -44,7 +57,27 @@ int TrackList::TrackCount()
|
||||
return tracks_.size();
|
||||
}
|
||||
|
||||
QVector<TrackPtr> TrackList::tracks()
|
||||
int TrackList::IndexOfTrack(Track *track)
|
||||
{
|
||||
for (int i=0;i<tracks_.size();i++) {
|
||||
if (tracks_.at(i) == track) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
Track *TrackList::TrackAt(int i)
|
||||
{
|
||||
while (i >= tracks_.size()) {
|
||||
AddTrack();
|
||||
}
|
||||
|
||||
return tracks_.at(i);
|
||||
}
|
||||
|
||||
QVector<Track*> TrackList::tracks()
|
||||
{
|
||||
return tracks_;
|
||||
}
|
||||
|
||||
@@ -10,10 +10,14 @@ public:
|
||||
TrackList(Sequence* parent, Track::Type type);
|
||||
TrackList* copy(Sequence* parent);
|
||||
|
||||
void Save(QXmlStreamWriter& stream);
|
||||
|
||||
void AddTrack();
|
||||
void RemoveTrack(int i);
|
||||
Track* First();
|
||||
int TrackCount();
|
||||
int IndexOfTrack(Track* track);
|
||||
Track* TrackAt(int i);
|
||||
QVector<Track*> tracks();
|
||||
|
||||
Sequence* GetParent();
|
||||
|
||||
+21
-2
@@ -1,9 +1,28 @@
|
||||
#include "timelinearea.h"
|
||||
|
||||
TimelineArea::TimelineArea() :
|
||||
track_list_(nullptr)
|
||||
track_list_(nullptr),
|
||||
alignment_(olive::timeline::kAlignmentTop)
|
||||
{
|
||||
QHBoxLayout* layout = new QHBoxLayout(this);
|
||||
|
||||
// LABELS
|
||||
QWidget* label_container = new QWidget();
|
||||
QVBoxLayout* label_container_layout = new QVBoxLayout(label_container);
|
||||
layout->addWidget(label_container);
|
||||
|
||||
// VIEW
|
||||
view_ = new TimelineView();
|
||||
layout->addWidget(view_);
|
||||
|
||||
// SCROLLBAR
|
||||
QScrollBar* scrollbar = new QScrollBar(Qt::Vertical);
|
||||
layout->addWidget(scrollbar);
|
||||
}
|
||||
|
||||
void TimelineArea::SetAlignment(olive::timeline::Alignment alignment)
|
||||
{
|
||||
alignment_ = alignment;
|
||||
}
|
||||
|
||||
void TimelineArea::SetTrackList(Sequence *sequence, Track::Type track_list)
|
||||
@@ -29,7 +48,7 @@ void TimelineArea::RefreshLabels()
|
||||
|
||||
labels_.resize(track_list_->TrackCount());
|
||||
for (int i=0;i<labels_.size();i++) {
|
||||
labels_.at(i).settra
|
||||
labels_[i].SetTrack(track_list_->TrackAt(i));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "timeline/sequence.h"
|
||||
#include "timeline/track.h"
|
||||
#include "timeline/tracklist.h"
|
||||
#include "timeline/timelinefunctions.h"
|
||||
#include "ui/timelineview.h"
|
||||
#include "ui/timelinelabel.h"
|
||||
|
||||
@@ -13,6 +14,7 @@ class TimelineArea : public QWidget
|
||||
public:
|
||||
TimelineArea();
|
||||
|
||||
void SetAlignment(olive::timeline::Alignment alignment);
|
||||
void SetTrackList(Sequence* sequence, Track::Type track_list);
|
||||
public slots:
|
||||
void RefreshLabels();
|
||||
@@ -20,6 +22,7 @@ private:
|
||||
TrackList* track_list_;
|
||||
TimelineView* view_;
|
||||
QVector<TimelineLabel> labels_;
|
||||
olive::timeline::Alignment alignment_;
|
||||
};
|
||||
|
||||
#endif // TIMELINEAREA_H
|
||||
|
||||
@@ -72,6 +72,8 @@ TimelineView::TimelineView(QWidget *parent) : QWidget(parent) {
|
||||
track_resizing = false;
|
||||
setMouseTracking(true);
|
||||
|
||||
setFocusPolicy(Qt::ClickFocus);
|
||||
|
||||
setAcceptDrops(true);
|
||||
|
||||
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ void draw_waveform(ClipPtr clip, const FootageStream *ms, long media_length, QPa
|
||||
class TimelineView : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TimelineView(QWidget *parent);
|
||||
explicit TimelineView(QWidget *parent = nullptr);
|
||||
|
||||
QScrollBar* scrollBar;
|
||||
bool bottom_align;
|
||||
|
||||
+10
-11
@@ -90,14 +90,12 @@ void MoveClipAction::doRedo() {
|
||||
}
|
||||
}
|
||||
|
||||
DeleteClipAction::DeleteClipAction(Sequence *s, int clip) {
|
||||
seq = s;
|
||||
index = clip;
|
||||
opening_transition = -1;
|
||||
closing_transition = -1;
|
||||
}
|
||||
DeleteClipAction::DeleteClipAction(Clip *clip)
|
||||
{
|
||||
// Get shared_ptr object to take ownership of this Clip
|
||||
|
||||
DeleteClipAction::~DeleteClipAction() {}
|
||||
clip_ = clip->track()->GetClipObjectFromRawPtr(clip);
|
||||
}
|
||||
|
||||
void DeleteClipAction::doUndo() {
|
||||
// restore ref to clip
|
||||
@@ -113,13 +111,14 @@ void DeleteClipAction::doUndo() {
|
||||
|
||||
void DeleteClipAction::doRedo() {
|
||||
// remove ref to clip
|
||||
ref = seq->clips.at(index);
|
||||
if (ref->IsOpen()) {
|
||||
ref->Close(true);
|
||||
if (clip_->IsOpen()) {
|
||||
clip_->Close(true);
|
||||
}
|
||||
seq->clips[index] = nullptr;
|
||||
|
||||
clip_->track()->RemoveClip(clip_.get());
|
||||
|
||||
// delete link to this clip
|
||||
QVector<Clip*> clips = clip_->track()->
|
||||
linkClipIndex.clear();
|
||||
linkLinkIndex.clear();
|
||||
for (int i=0;i<seq->clips.size();i++) {
|
||||
|
||||
+3
-10
@@ -113,20 +113,13 @@ private:
|
||||
|
||||
class DeleteClipAction : public OliveAction {
|
||||
public:
|
||||
DeleteClipAction(Sequence* s, int clip);
|
||||
virtual ~DeleteClipAction() override;
|
||||
DeleteClipAction(Clip* clip);
|
||||
virtual void doUndo() override;
|
||||
virtual void doRedo() override;
|
||||
private:
|
||||
Sequence* seq;
|
||||
ClipPtr ref;
|
||||
int index;
|
||||
ClipPtr clip_;
|
||||
|
||||
int opening_transition;
|
||||
int closing_transition;
|
||||
|
||||
QVector<int> linkClipIndex;
|
||||
QVector<int> linkLinkIndex;
|
||||
QVector<Clip*> clips_linked_to_this_one_;
|
||||
};
|
||||
|
||||
class ChangeSequenceAction : public OliveAction {
|
||||
|
||||
Reference in New Issue
Block a user