rewrite work continued
This commit is contained in:
@@ -174,7 +174,9 @@ SOURCES += \
|
||||
rendering/shadergenerators.cpp \
|
||||
global/timing.cpp \
|
||||
rendering/pixelformats.cpp \
|
||||
timeline/timelinefunctions.cpp
|
||||
timeline/timelinefunctions.cpp \
|
||||
timeline/track.cpp \
|
||||
timeline/tracklist.cpp
|
||||
|
||||
HEADERS += \
|
||||
ui/mainwindow.h \
|
||||
@@ -308,7 +310,9 @@ HEADERS += \
|
||||
global/timing.h \
|
||||
rendering/pixelformats.h \
|
||||
timeline/ghost.h \
|
||||
timeline/timelinefunctions.h
|
||||
timeline/timelinefunctions.h \
|
||||
timeline/track.h \
|
||||
timeline/tracklist.h
|
||||
|
||||
FORMS +=
|
||||
|
||||
|
||||
@@ -646,11 +646,11 @@ void EffectControls::Load() {
|
||||
}
|
||||
}
|
||||
if (c->opening_transition != nullptr
|
||||
&& (whole_clip_is_selected || c->sequence->IsTransitionSelected(c->opening_transition.get()))) {
|
||||
&& (whole_clip_is_selected || c->track()->IsTransitionSelected(c->opening_transition.get()))) {
|
||||
effects_to_open.append(c->opening_transition.get());
|
||||
}
|
||||
if (c->closing_transition != nullptr
|
||||
&& (whole_clip_is_selected || c->sequence->IsTransitionSelected(c->closing_transition.get()))) {
|
||||
&& (whole_clip_is_selected || c->track()->IsTransitionSelected(c->closing_transition.get()))) {
|
||||
effects_to_open.append(c->closing_transition.get());
|
||||
}
|
||||
|
||||
|
||||
+27
-162
@@ -492,21 +492,6 @@ MediaPtr Project::item_to_media_ptr(const QModelIndex &index) {
|
||||
return raw_ptr->parentItem()->get_shared_ptr(raw_ptr);
|
||||
}
|
||||
|
||||
void Project::get_all_media_from_table(QList<Media*>& items, QList<Media*>& list, int search_type) {
|
||||
for (int i=0;i<items.size();i++) {
|
||||
Media* item = items.at(i);
|
||||
if (item->get_type() == MEDIA_TYPE_FOLDER) {
|
||||
QList<Media*> children;
|
||||
for (int j=0;j<item->childCount();j++) {
|
||||
children.append(item->child(j));
|
||||
}
|
||||
get_all_media_from_table(children, list, search_type);
|
||||
} else if (search_type == item->get_type() || search_type == -1) {
|
||||
list.append(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Project::IsToolbarVisible()
|
||||
{
|
||||
return toolbar_widget->isVisible();
|
||||
@@ -550,25 +535,22 @@ void Project::delete_selected_media() {
|
||||
|
||||
// check if media is in use
|
||||
QVector<Media*> parents;
|
||||
QList<Media*> sequence_items;
|
||||
QList<Media*> all_top_level_items;
|
||||
for (int i=0;i<olive::project_model.childCount();i++) {
|
||||
all_top_level_items.append(olive::project_model.child(i));
|
||||
}
|
||||
get_all_media_from_table(all_top_level_items, sequence_items, MEDIA_TYPE_SEQUENCE); // find all sequences in project
|
||||
if (sequence_items.size() > 0) {
|
||||
QVector<Media*> all_sequences = olive::project_model.GetAllSequences();
|
||||
if (all_sequences.size() > 0) {
|
||||
|
||||
QList<Media*> media_items;
|
||||
get_all_media_from_table(items, media_items, MEDIA_TYPE_FOOTAGE);
|
||||
QVector<Media*> all_footage = olive::project_model.GetAllFootage();
|
||||
|
||||
for (int i=0;i<media_items.size();i++) {
|
||||
Media* item = media_items.at(i);
|
||||
for (int i=0;i<all_footage.size();i++) {
|
||||
Media* item = all_footage.at(i);
|
||||
Footage* media = item->to_footage();
|
||||
bool confirm_delete = false;
|
||||
for (int j=0;j<sequence_items.size();j++) {
|
||||
Sequence* s = sequence_items.at(j)->to_sequence().get();
|
||||
for (int k=0;k<s->clips.size();k++) {
|
||||
ClipPtr c = s->clips.at(k);
|
||||
for (int j=0;j<all_sequences.size();j++) {
|
||||
|
||||
Sequence* s = all_sequences.at(j)->to_sequence().get();
|
||||
QVector<Clip*> sequence_clips = s->GetAllClips();
|
||||
|
||||
for (int k=0;k<sequence_clips.size();k++) {
|
||||
Clip* c = sequence_clips.at(k);
|
||||
if (c != nullptr && c->media() == item) {
|
||||
if (!confirm_delete) {
|
||||
// we found a reference, so we know we'll need to ask if the user wants to delete it
|
||||
@@ -608,13 +590,13 @@ void Project::delete_selected_media() {
|
||||
parent = parent->parentItem();
|
||||
}
|
||||
|
||||
j = sequence_items.size();
|
||||
k = s->clips.size();
|
||||
j = all_sequences.size();
|
||||
k = sequence_clips.size();
|
||||
} else if (confirm.clickedButton() == abort_button) {
|
||||
// break out of loop
|
||||
i = media_items.size();
|
||||
j = sequence_items.size();
|
||||
k = s->clips.size();
|
||||
i = all_footage.size();
|
||||
j = all_sequences.size();
|
||||
k = sequence_clips.size();
|
||||
|
||||
remove = false;
|
||||
}
|
||||
@@ -636,7 +618,9 @@ void Project::delete_selected_media() {
|
||||
panel_graph_editor->set_row(nullptr);
|
||||
panel_effect_controls->Clear(true);
|
||||
|
||||
if (olive::ActiveSequence != nullptr) olive::ActiveSequence->selections.clear();
|
||||
if (olive::ActiveSequence != nullptr) {
|
||||
olive::ActiveSequence->ClearSelections();
|
||||
}
|
||||
|
||||
// remove media and parents
|
||||
for (int m=0;m<parents.size();m++) {
|
||||
@@ -665,14 +649,8 @@ void Project::delete_selected_media() {
|
||||
panel_footage_viewer->set_media(nullptr);
|
||||
}
|
||||
} else if (items.at(i)->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
if (panel_footage_viewer->seq != nullptr) {
|
||||
for (int j=0;j<panel_footage_viewer->seq->clips.size();j++) {
|
||||
ClipPtr c = panel_footage_viewer->seq->clips.at(j);
|
||||
if (c != nullptr && c->media() == items.at(i)) {
|
||||
panel_footage_viewer->set_media(nullptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (panel_footage_viewer->media == items.at(i)) {
|
||||
panel_footage_viewer->set_media(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1023,8 +1001,9 @@ void Project::delete_clips_using_selected_media() {
|
||||
ComboAction* ca = new ComboAction();
|
||||
bool deleted = false;
|
||||
QModelIndexList items = get_current_selected();
|
||||
for (int i=0;i<olive::ActiveSequence->clips.size();i++) {
|
||||
const ClipPtr& c = olive::ActiveSequence->clips.at(i);
|
||||
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));
|
||||
@@ -1068,13 +1047,6 @@ void Project::clear() {
|
||||
tree_view->update();
|
||||
}
|
||||
|
||||
void save_marker(QXmlStreamWriter& stream, const Marker& m) {
|
||||
stream.writeStartElement("marker");
|
||||
stream.writeAttribute("frame", QString::number(m.frame));
|
||||
stream.writeAttribute("name", m.name);
|
||||
stream.writeEndElement();
|
||||
}
|
||||
|
||||
void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only, const QModelIndex& parent) {
|
||||
for (int i=0;i<olive::project_model.rowCount(parent);i++) {
|
||||
const QModelIndex& item = olive::project_model.index(i, 0, parent);
|
||||
@@ -1145,7 +1117,7 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only,
|
||||
|
||||
// save footage markers
|
||||
for (int j=0;j<f->markers.size();j++) {
|
||||
save_marker(stream, f->markers.at(j));
|
||||
f->markers.at(j).Save(stream);
|
||||
}
|
||||
|
||||
stream.writeEndElement(); // footage
|
||||
@@ -1156,114 +1128,7 @@ void Project::save_folder(QXmlStreamWriter& stream, int type, bool set_ids_only,
|
||||
s->save_id = sequence_id;
|
||||
sequence_id++;
|
||||
} else {
|
||||
stream.writeStartElement("sequence");
|
||||
stream.writeAttribute("id", QString::number(s->save_id));
|
||||
stream.writeAttribute("folder", QString::number(folder));
|
||||
stream.writeAttribute("name", s->name);
|
||||
stream.writeAttribute("width", QString::number(s->width));
|
||||
stream.writeAttribute("height", QString::number(s->height));
|
||||
stream.writeAttribute("framerate", QString::number(s->frame_rate, 'f', 10));
|
||||
stream.writeAttribute("afreq", QString::number(s->audio_frequency));
|
||||
stream.writeAttribute("alayout", QString::number(s->audio_layout));
|
||||
if (s == olive::ActiveSequence.get()) {
|
||||
stream.writeAttribute("open", "1");
|
||||
}
|
||||
stream.writeAttribute("workarea", QString::number(s->using_workarea));
|
||||
stream.writeAttribute("workareaIn", QString::number(s->workarea_in));
|
||||
stream.writeAttribute("workareaOut", QString::number(s->workarea_out));
|
||||
|
||||
QVector<TransitionPtr> transition_save_cache;
|
||||
QVector<int> transition_clip_save_cache;
|
||||
|
||||
for (int j=0;j<s->clips.size();j++) {
|
||||
const ClipPtr& c = s->clips.at(j);
|
||||
if (c != nullptr) {
|
||||
stream.writeStartElement("clip"); // clip
|
||||
stream.writeAttribute("id", QString::number(j));
|
||||
stream.writeAttribute("enabled", QString::number(c->enabled()));
|
||||
stream.writeAttribute("name", c->name());
|
||||
stream.writeAttribute("clipin", QString::number(c->clip_in()));
|
||||
stream.writeAttribute("in", QString::number(c->timeline_in()));
|
||||
stream.writeAttribute("out", QString::number(c->timeline_out()));
|
||||
stream.writeAttribute("track", QString::number(c->track()));
|
||||
|
||||
stream.writeAttribute("r", QString::number(c->color().red()));
|
||||
stream.writeAttribute("g", QString::number(c->color().green()));
|
||||
stream.writeAttribute("b", QString::number(c->color().blue()));
|
||||
|
||||
stream.writeAttribute("autoscale", QString::number(c->autoscaled()));
|
||||
stream.writeAttribute("speed", QString::number(c->speed().value, 'f', 10));
|
||||
stream.writeAttribute("maintainpitch", QString::number(c->speed().maintain_audio_pitch));
|
||||
stream.writeAttribute("reverse", QString::number(c->reversed()));
|
||||
|
||||
if (c->media() != nullptr) {
|
||||
stream.writeAttribute("type", QString::number(c->media()->get_type()));
|
||||
switch (c->media()->get_type()) {
|
||||
case MEDIA_TYPE_FOOTAGE:
|
||||
stream.writeAttribute("media", QString::number(c->media()->to_footage()->save_id));
|
||||
stream.writeAttribute("stream", QString::number(c->media_stream_index()));
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
stream.writeAttribute("sequence", QString::number(c->media()->to_sequence()->save_id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// save markers
|
||||
// only necessary for null media clips, since media has its own markers
|
||||
if (c->media() == nullptr) {
|
||||
for (int k=0;k<c->get_markers().size();k++) {
|
||||
save_marker(stream, c->get_markers().at(k));
|
||||
}
|
||||
}
|
||||
|
||||
// save clip links
|
||||
stream.writeStartElement("linked"); // linked
|
||||
for (int k=0;k<c->linked.size();k++) {
|
||||
stream.writeStartElement("link"); // link
|
||||
stream.writeAttribute("id", QString::number(c->linked.at(k)));
|
||||
stream.writeEndElement(); // link
|
||||
}
|
||||
stream.writeEndElement(); // linked
|
||||
|
||||
// save opening and closing transitions
|
||||
for (int t=kTransitionOpening;t<=kTransitionClosing;t++) {
|
||||
TransitionPtr transition = (t == kTransitionOpening) ? c->opening_transition : c->closing_transition;
|
||||
|
||||
if (transition != nullptr) {
|
||||
stream.writeStartElement((t == kTransitionOpening) ? "opening" : "closing");
|
||||
|
||||
// check if this is a shared transition and the transition has already been saved
|
||||
int transition_cache_index = transition_save_cache.indexOf(transition);
|
||||
|
||||
if (transition_cache_index > -1) {
|
||||
// if so, just save a reference to the other clip
|
||||
stream.writeAttribute("shared",
|
||||
QString::number(transition_clip_save_cache.at(transition_cache_index)));
|
||||
} else {
|
||||
// otherwise save the whole transition
|
||||
transition->save(stream);
|
||||
transition_save_cache.append(transition);
|
||||
transition_clip_save_cache.append(j);
|
||||
}
|
||||
|
||||
stream.writeEndElement(); // opening
|
||||
}
|
||||
}
|
||||
|
||||
for (int k=0;k<c->effects.size();k++) {
|
||||
stream.writeStartElement("effect"); // effect
|
||||
c->effects.at(k)->save(stream);
|
||||
stream.writeEndElement(); // effect
|
||||
}
|
||||
|
||||
stream.writeEndElement(); // clip
|
||||
}
|
||||
}
|
||||
for (int j=0;j<s->markers.size();j++) {
|
||||
save_marker(stream, s->markers.at(j));
|
||||
}
|
||||
stream.writeEndElement();
|
||||
s->Save(stream);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,8 +81,6 @@ public:
|
||||
|
||||
QModelIndexList get_current_selected();
|
||||
|
||||
void get_all_media_from_table(QList<Media *> &items, QList<Media *> &list, int type = -1);
|
||||
|
||||
bool IsToolbarVisible();
|
||||
bool IsProjectWidget(QObject *child);
|
||||
|
||||
|
||||
+1
-7
@@ -56,10 +56,6 @@
|
||||
#include "global/timing.h"
|
||||
#include "ui/menu.h"
|
||||
|
||||
int olive::timeline::kTrackDefaultHeight = 40;
|
||||
int olive::timeline::kTrackMinHeight = 30;
|
||||
int olive::timeline::kTrackHeightIncrement = 10;
|
||||
|
||||
Timeline::Timeline(QWidget *parent) :
|
||||
Panel(parent),
|
||||
cursor_frame(0),
|
||||
@@ -119,8 +115,6 @@ Timeline::Timeline(QWidget *parent) :
|
||||
Retranslate();
|
||||
}
|
||||
|
||||
Timeline::~Timeline() {}
|
||||
|
||||
void Timeline::Retranslate() {
|
||||
toolArrowButton->setToolTip(tr("Pointer Tool") + " (V)");
|
||||
toolEditButton->setToolTip(tr("Edit Tool") + " (X)");
|
||||
@@ -270,7 +264,7 @@ void Timeline::create_ghosts_from_media(Sequence* seq, long entry_point, QVector
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
s = medium->to_sequence().get();
|
||||
sequence_length = s->getEndFrame();
|
||||
sequence_length = s->GetEndFrame();
|
||||
if (seq != nullptr) sequence_length = rescale_frame_number(sequence_length, s->frame_rate, seq->frame_rate);
|
||||
can_import = (s != seq && sequence_length != 0);
|
||||
if (s->using_workarea) {
|
||||
|
||||
@@ -38,28 +38,6 @@
|
||||
#include "ui/panel.h"
|
||||
|
||||
|
||||
|
||||
namespace olive {
|
||||
namespace timeline {
|
||||
const int kGhostThickness = 2;
|
||||
const int kClipTextPadding = 3;
|
||||
|
||||
/**
|
||||
* @brief Set default track sizes
|
||||
*
|
||||
* Olive has a few default constants used for adjusting track heights in the Timeline. For HiDPI, it makes
|
||||
* sense to multiply these by the current DPI scale. It uses a variable from QApplication to do this multiplication,
|
||||
* which means the QApplication instance needs to be instantiated before these are calculated. Therefore, call this
|
||||
* function ONCE after QApplication is created to multiply the track heights correctly.
|
||||
*/
|
||||
void MultiplyTrackSizesByDPI();
|
||||
|
||||
extern int kTrackDefaultHeight;
|
||||
extern int kTrackMinHeight;
|
||||
extern int kTrackHeightIncrement;
|
||||
}
|
||||
}
|
||||
|
||||
int getScreenPointFromFrame(double zoom, long frame);
|
||||
long getFrameFromScreenPoint(double zoom, int x);
|
||||
bool selection_contains_transition(const Selection& s, Clip *c, int type);
|
||||
@@ -72,7 +50,6 @@ class Timeline : public Panel
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Timeline(QWidget *parent = nullptr);
|
||||
virtual ~Timeline() override;
|
||||
|
||||
bool focused();
|
||||
void multiply_zoom(double m);
|
||||
@@ -255,8 +232,6 @@ private:
|
||||
long rc_ripple_min;
|
||||
long rc_ripple_max;
|
||||
|
||||
QVector<TimelineTrackHeight> track_heights;
|
||||
|
||||
QWidget* timeline_area;
|
||||
TimelineWidget* video_area;
|
||||
TimelineWidget* audio_area;
|
||||
|
||||
+25
-20
@@ -127,12 +127,15 @@ void Viewer::reset_all_audio() {
|
||||
// reset all clip audio
|
||||
if (seq != nullptr) {
|
||||
long last_frame = 0;
|
||||
for (int i=0;i<seq->clips.size();i++) {
|
||||
ClipPtr c = seq->clips.at(i);
|
||||
if (c != nullptr) {
|
||||
c->reset_audio();
|
||||
last_frame = qMax(last_frame, c->timeline_out());
|
||||
}
|
||||
|
||||
QVector<Clip*> all_clips = seq->GetAllClips();
|
||||
for (int i=0;i<all_clips.size();i++) {
|
||||
|
||||
Clip* c = all_clips.at(i);
|
||||
|
||||
c->reset_audio();
|
||||
last_frame = qMax(last_frame, c->timeline_out());
|
||||
|
||||
}
|
||||
|
||||
audio_ibuffer_frame = seq->playhead;
|
||||
@@ -149,7 +152,7 @@ void Viewer::seek(long p) {
|
||||
if (main_sequence) {
|
||||
seq->playhead = p;
|
||||
} else {
|
||||
seq->playhead = qMin(seq->getEndFrame(), qMax(0L, p));
|
||||
seq->playhead = qMin(seq->GetEndFrame(), qMax(0L, p));
|
||||
}
|
||||
bool update_fx = false;
|
||||
if (main_sequence) {
|
||||
@@ -171,7 +174,7 @@ void Viewer::go_to_start() {
|
||||
}
|
||||
|
||||
void Viewer::go_to_end() {
|
||||
if (seq != nullptr) seek(seq->getEndFrame());
|
||||
if (seq != nullptr) seek(seq->GetEndFrame());
|
||||
}
|
||||
|
||||
void Viewer::close_media() {
|
||||
@@ -206,7 +209,7 @@ void Viewer::go_to_out() {
|
||||
}
|
||||
}
|
||||
|
||||
void Viewer::cue_recording(long start, long end, int track) {
|
||||
void Viewer::cue_recording(long start, long end, Track* track) {
|
||||
recording_start = start;
|
||||
recording_end = end;
|
||||
recording_track = track;
|
||||
@@ -257,7 +260,7 @@ void Viewer::play(bool in_to_out) {
|
||||
if (panel_sequence_viewer->playing) panel_sequence_viewer->pause();
|
||||
if (panel_footage_viewer->playing) panel_footage_viewer->pause();
|
||||
|
||||
long sequence_end_frame = seq->getEndFrame();
|
||||
long sequence_end_frame = seq->GetEndFrame();
|
||||
if (sequence_end_frame == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -353,12 +356,12 @@ void Viewer::update_playhead_timecode(long p) {
|
||||
}
|
||||
|
||||
void Viewer::update_end_timecode() {
|
||||
end_timecode->setText((seq == nullptr) ? frame_to_timecode(0, olive::CurrentConfig.timecode_view, 30) : frame_to_timecode(seq->getEndFrame(), olive::CurrentConfig.timecode_view, seq->frame_rate));
|
||||
end_timecode->setText((seq == nullptr) ? frame_to_timecode(0, olive::CurrentConfig.timecode_view, 30) : frame_to_timecode(seq->GetEndFrame(), olive::CurrentConfig.timecode_view, seq->frame_rate));
|
||||
}
|
||||
|
||||
void Viewer::update_header_zoom() {
|
||||
if (seq != nullptr) {
|
||||
long sequenceEndFrame = seq->getEndFrame();
|
||||
long sequenceEndFrame = seq->GetEndFrame();
|
||||
if (cached_end_frame != sequenceEndFrame) {
|
||||
minimum_zoom = (sequenceEndFrame > 0) ? ((double) headers->width() / (double) sequenceEndFrame) : 1;
|
||||
headers->update_zoom(qMax(headers->get_zoom(), minimum_zoom));
|
||||
@@ -431,7 +434,7 @@ void Viewer::clear_in() {
|
||||
void Viewer::clear_out() {
|
||||
if (seq != nullptr
|
||||
&& seq->using_workarea) {
|
||||
olive::UndoStack.push(new SetTimelineInOutCommand(seq.get(), true, seq->workarea_in, seq->getEndFrame()));
|
||||
olive::UndoStack.push(new SetTimelineInOutCommand(seq.get(), true, seq->workarea_in, seq->GetEndFrame()));
|
||||
update_parents();
|
||||
}
|
||||
}
|
||||
@@ -497,7 +500,7 @@ void Viewer::set_zoom_value(double d) {
|
||||
}
|
||||
|
||||
void Viewer::set_sb_max() {
|
||||
headers->set_scrollbar_max(horizontal_bar, seq->getEndFrame(), headers->width());
|
||||
headers->set_scrollbar_max(horizontal_bar, seq->GetEndFrame(), headers->width());
|
||||
}
|
||||
|
||||
void Viewer::set_playback_speed(int s) {
|
||||
@@ -517,7 +520,7 @@ long Viewer::get_seq_in() {
|
||||
long Viewer::get_seq_out() {
|
||||
return ((olive::CurrentConfig.loop || playing_in_to_out) && seq->using_workarea && previous_playhead < seq->workarea_out)
|
||||
? seq->workarea_out
|
||||
: seq->getEndFrame();
|
||||
: seq->GetEndFrame();
|
||||
}
|
||||
|
||||
void Viewer::setup_ui() {
|
||||
@@ -689,10 +692,11 @@ void Viewer::set_media(Media* m) {
|
||||
// FIXME: Move this magic number to Config
|
||||
c->set_timeline_out(150);
|
||||
}
|
||||
c->set_track(-1);
|
||||
Track* track = new_sequence->GetTrackList(Track::kTypeVideo)->First();
|
||||
c->set_track(track);
|
||||
c->set_clip_in(0);
|
||||
c->refresh();
|
||||
new_sequence->clips.append(c);
|
||||
track->AddClip(c);
|
||||
} else {
|
||||
new_sequence->width = olive::CurrentConfig.default_sequence_width;
|
||||
new_sequence->height = olive::CurrentConfig.default_sequence_height;
|
||||
@@ -706,10 +710,11 @@ void Viewer::set_media(Media* m) {
|
||||
c->set_media(media, audio_stream.file_index);
|
||||
c->set_timeline_in(0);
|
||||
c->set_timeline_out(footage->get_length_in_frames(new_sequence->frame_rate));
|
||||
c->set_track(0);
|
||||
Track* track = new_sequence->GetTrackList(Track::kTypeAudio)->First();
|
||||
c->set_track(track);
|
||||
c->set_clip_in(0);
|
||||
c->refresh();
|
||||
new_sequence->clips.append(c);
|
||||
track->AddClip(c);
|
||||
|
||||
if (footage->video_tracks.size() == 0) {
|
||||
viewer_widget_->waveform = true;
|
||||
@@ -756,7 +761,7 @@ void Viewer::timer_update() {
|
||||
pause();
|
||||
}
|
||||
} else if (playback_speed > 0) {
|
||||
long end_frame = seq->getEndFrame();
|
||||
long end_frame = seq->GetEndFrame();
|
||||
if ((olive::CurrentConfig.auto_seek_to_beginning || previous_playhead < end_frame) && seq->playhead >= end_frame) {
|
||||
pause();
|
||||
}
|
||||
|
||||
+2
-2
@@ -72,12 +72,12 @@ public:
|
||||
QTimer playback_updater;
|
||||
|
||||
|
||||
void cue_recording(long start, long end, int track);
|
||||
void cue_recording(long start, long end, Track *track);
|
||||
void uncue_recording();
|
||||
bool is_recording_cued();
|
||||
long recording_start;
|
||||
long recording_end;
|
||||
int recording_track;
|
||||
Track* recording_track;
|
||||
|
||||
void reset_all_audio();
|
||||
void update_parents(bool reload_fx = false);
|
||||
|
||||
+1
-1
@@ -293,7 +293,7 @@ int Media::columnCount() const {
|
||||
QString Media::GetStringDuration() {
|
||||
if (get_type() == MEDIA_TYPE_SEQUENCE) {
|
||||
Sequence* s = to_sequence().get();
|
||||
return frame_to_timecode(s->getEndFrame(), olive::CurrentConfig.timecode_view, s->frame_rate);
|
||||
return frame_to_timecode(s->GetEndFrame(), olive::CurrentConfig.timecode_view, s->frame_rate);
|
||||
}
|
||||
if (get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
Footage* f = to_footage();
|
||||
|
||||
@@ -50,7 +50,7 @@ void ProjectModel::destroy_root() {
|
||||
panel_footage_viewer->set_media(nullptr);
|
||||
}
|
||||
|
||||
root_item_ = std::make_shared<Media>();
|
||||
root_item_ = nullptr;
|
||||
}
|
||||
|
||||
void ProjectModel::clear() {
|
||||
@@ -196,6 +196,44 @@ void ProjectModel::set_icon(Media* m, const QIcon &ico) {
|
||||
emit dataChanged(index, index);
|
||||
}
|
||||
|
||||
QVector<Media *> ProjectModel::GetAllSequences()
|
||||
{
|
||||
return GetAllMediaOfType(MEDIA_TYPE_SEQUENCE);
|
||||
}
|
||||
|
||||
QVector<Media *> ProjectModel::GetAllFootage()
|
||||
{
|
||||
return GetAllMediaOfType(MEDIA_TYPE_FOOTAGE);
|
||||
}
|
||||
|
||||
QVector<Media *> ProjectModel::GetAllFolders()
|
||||
{
|
||||
return GetAllMediaOfType(MEDIA_TYPE_FOLDER);
|
||||
}
|
||||
|
||||
QVector<Media *> ProjectModel::GetAllMediaOfType(int search_type)
|
||||
{
|
||||
QVector<Media*> media_list;
|
||||
RecurseTree(root_item_.get(), media_list, search_type);
|
||||
return media_list;
|
||||
}
|
||||
|
||||
void ProjectModel::RecurseTree(Media* parent, QVector<Media*>& list, int search_type)
|
||||
{
|
||||
for (int i=0;i<parent->childCount();i++) {
|
||||
|
||||
Media* child = parent->child(i);
|
||||
|
||||
if (child->get_type() == search_type) {
|
||||
list.append(child);
|
||||
}
|
||||
|
||||
if (child->childCount() > 0) {
|
||||
RecurseTree(child, list, search_type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ProjectModel::appendChild(Media* parent, MediaPtr child) {
|
||||
QModelIndex row_start;
|
||||
|
||||
|
||||
@@ -58,8 +58,15 @@ public:
|
||||
int childCount(Media* parent = nullptr);
|
||||
void set_icon(Media* m, const QIcon &ico);
|
||||
|
||||
QVector<Media*> GetAllSequences();
|
||||
QVector<Media*> GetAllFootage();
|
||||
QVector<Media*> GetAllFolders();
|
||||
|
||||
private:
|
||||
MediaPtr root_item_;
|
||||
|
||||
QVector<Media*> GetAllMediaOfType(int search_type);
|
||||
void RecurseTree(Media* parent, QVector<Media *> &list, int search_type);
|
||||
};
|
||||
|
||||
namespace olive {
|
||||
|
||||
@@ -144,7 +144,7 @@ void Cacher::CacheAudioWorker() {
|
||||
}
|
||||
|
||||
if (temp_reverse) {
|
||||
long seq_end = olive::ActiveSequence->getEndFrame();
|
||||
long seq_end = olive::ActiveSequence->GetEndFrame();
|
||||
timeline_in = seq_end - timeline_in;
|
||||
timeline_out = seq_end - timeline_out;
|
||||
target_frame = seq_end - target_frame;
|
||||
|
||||
+113
-23
@@ -37,14 +37,13 @@
|
||||
#include "global/debug.h"
|
||||
#include "global/timing.h"
|
||||
|
||||
Clip::Clip(Sequence* s) :
|
||||
sequence(s),
|
||||
Clip::Clip(Track *s) :
|
||||
track_(s),
|
||||
cacher(this),
|
||||
enabled_(true),
|
||||
clip_in_(0),
|
||||
timeline_in_(0),
|
||||
timeline_out_(0),
|
||||
track_(0),
|
||||
media_(nullptr),
|
||||
reverse_(false),
|
||||
autoscale_(olive::CurrentConfig.autoscale_by_default),
|
||||
@@ -57,7 +56,7 @@ Clip::Clip(Sequence* s) :
|
||||
{
|
||||
}
|
||||
|
||||
ClipPtr Clip::copy(Sequence* s) {
|
||||
ClipPtr Clip::copy(Track* s) {
|
||||
ClipPtr copy = std::make_shared<Clip>(s);
|
||||
|
||||
copy->set_enabled(enabled());
|
||||
@@ -76,7 +75,7 @@ ClipPtr Clip::copy(Sequence* s) {
|
||||
copy->effects.append(effects.at(i)->copy(copy.get()));
|
||||
}
|
||||
|
||||
copy->set_cached_frame_rate((this->sequence == nullptr) ? cached_frame_rate() : this->sequence->frame_rate);
|
||||
copy->set_cached_frame_rate((this->track_ == nullptr) ? cached_frame_rate() : this->track_->frame_rate);
|
||||
|
||||
copy->refresh();
|
||||
|
||||
@@ -85,25 +84,36 @@ ClipPtr Clip::copy(Sequence* s) {
|
||||
|
||||
bool Clip::IsActiveAt(long timecode)
|
||||
{
|
||||
// these buffers allow clips to be opened and prepared well before they're displayed
|
||||
// as well as closed a little after they're not needed anymore
|
||||
int open_buffer = qCeil(this->sequence->frame_rate*2);
|
||||
int close_buffer = qCeil(this->sequence->frame_rate);
|
||||
|
||||
|
||||
return enabled()
|
||||
&& timeline_in(true) < timecode + open_buffer
|
||||
&& timeline_out(true) > timecode - close_buffer
|
||||
&& timeline_in(true) < timecode
|
||||
&& timeline_out(true) > timecode
|
||||
&& timecode - timeline_in(true) + clip_in(true) < media_length();
|
||||
}
|
||||
|
||||
bool Clip::IsSelected(bool containing)
|
||||
{
|
||||
if (this->sequence == nullptr) {
|
||||
if (this->track_ == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this->sequence->IsClipSelected(this, containing);
|
||||
return this->track_->IsClipSelected(this, containing);
|
||||
}
|
||||
|
||||
bool Clip::IsTransitionSelected(TransitionType type)
|
||||
{
|
||||
switch (type) {
|
||||
case kTransitionOpening:
|
||||
return track_->IsTransitionSelected(opening_transition.get());
|
||||
case kTransitionClosing:
|
||||
return track_->IsTransitionSelected(closing_transition.get());
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Track::Type Clip::type()
|
||||
{
|
||||
return track()->type();
|
||||
}
|
||||
|
||||
const QColor &Clip::color()
|
||||
@@ -132,7 +142,7 @@ FootageStream *Clip::media_stream()
|
||||
{
|
||||
if (media() != nullptr
|
||||
&& media()->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
return media()->to_footage()->get_stream_from_file_index(track() < 0, media_stream_index());
|
||||
return media()->to_footage()->get_stream_from_file_index(type() == Track::kTypeVideo, media_stream_index());
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
@@ -212,9 +222,9 @@ void Clip::refresh() {
|
||||
if (replaced && media() != nullptr && media()->get_type() == MEDIA_TYPE_FOOTAGE) {
|
||||
Footage* m = media()->to_footage();
|
||||
|
||||
if (track() < 0 && m->video_tracks.size() > 0) {
|
||||
if (type() == Track::kTypeVideo && m->video_tracks.size() > 0) {
|
||||
set_media(media(), m->video_tracks.at(0).file_index);
|
||||
} else if (track() >= 0 && m->audio_tracks.size() > 0) {
|
||||
} else if (type() == Track::kTypeAudio && m->audio_tracks.size() > 0) {
|
||||
set_media(media(), m->audio_tracks.at(0).file_index);
|
||||
}
|
||||
}
|
||||
@@ -247,8 +257,88 @@ Clip::~Clip() {
|
||||
if (IsOpen()) {
|
||||
Close(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Clip::Save(QXmlStreamWriter &stream)
|
||||
{
|
||||
stream.writeAttribute("enabled", QString::number(enabled()));
|
||||
stream.writeAttribute("name", name());
|
||||
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()));
|
||||
stream.writeAttribute("b", QString::number(color().blue()));
|
||||
|
||||
stream.writeAttribute("autoscale", QString::number(autoscaled()));
|
||||
stream.writeAttribute("speed", QString::number(speed().value, 'f', 10));
|
||||
stream.writeAttribute("maintainpitch", QString::number(speed().maintain_audio_pitch));
|
||||
stream.writeAttribute("reverse", QString::number(reversed()));
|
||||
|
||||
if (c->media() != nullptr) {
|
||||
stream.writeAttribute("type", QString::number(media()->get_type()));
|
||||
switch (c->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()));
|
||||
break;
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
stream.writeAttribute("sequence", QString::number(media()->to_sequence()->save_id));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// save markers
|
||||
// only necessary for null media clips, since media has its own markers
|
||||
if (media() == nullptr) {
|
||||
for (int k=0;k<get_markers().size();k++) {
|
||||
get_markers().at(k).Save(stream);
|
||||
}
|
||||
}
|
||||
|
||||
// save clip links
|
||||
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.writeEndElement(); // link
|
||||
}
|
||||
stream.writeEndElement(); // linked
|
||||
|
||||
// save opening and closing transitions
|
||||
for (int t=kTransitionOpening;t<=kTransitionClosing;t++) {
|
||||
TransitionPtr transition = (t == kTransitionOpening) ? opening_transition : closing_transition;
|
||||
|
||||
if (transition != nullptr) {
|
||||
stream.writeStartElement((t == kTransitionOpening) ? "opening" : "closing");
|
||||
|
||||
// check if this is a shared transition and the transition has already been saved
|
||||
int transition_cache_index = transition_save_cache.indexOf(transition);
|
||||
|
||||
if (transition_cache_index > -1) {
|
||||
// if so, just save a reference to the other clip
|
||||
stream.writeAttribute("shared",
|
||||
QString::number(transition_clip_save_cache.at(transition_cache_index)));
|
||||
} else {
|
||||
// otherwise save the whole transition
|
||||
transition->save(stream);
|
||||
transition_save_cache.append(transition);
|
||||
transition_clip_save_cache.append(j);
|
||||
}
|
||||
|
||||
stream.writeEndElement(); // opening
|
||||
}
|
||||
}
|
||||
|
||||
for (int k=0;k<effects.size();k++) {
|
||||
stream.writeStartElement("effect"); // effect
|
||||
effects.at(k)->save(stream);
|
||||
stream.writeEndElement(); // effect
|
||||
}
|
||||
|
||||
|
||||
effects.clear();
|
||||
}
|
||||
|
||||
long Clip::clip_in(bool with_transition) {
|
||||
@@ -346,12 +436,12 @@ AVRational Clip::time_base()
|
||||
return cacher.media_time_base();
|
||||
}
|
||||
|
||||
int Clip::track()
|
||||
Track *Clip::track()
|
||||
{
|
||||
return track_;
|
||||
}
|
||||
|
||||
void Clip::set_track(int t)
|
||||
void Clip::set_track(Track *t)
|
||||
{
|
||||
track_ = t;
|
||||
}
|
||||
@@ -362,7 +452,7 @@ long Clip::length() {
|
||||
}
|
||||
|
||||
double Clip::media_frame_rate() {
|
||||
Q_ASSERT(track_ < 0);
|
||||
Q_ASSERT(type() == Track::kTypeVideo);
|
||||
if (media_ != nullptr) {
|
||||
double rate = media_->get_frame_rate(media_stream_index());
|
||||
if (!qIsNaN(rate)) return rate;
|
||||
@@ -394,7 +484,7 @@ long Clip::media_length() {
|
||||
case MEDIA_TYPE_SEQUENCE:
|
||||
{
|
||||
Sequence* s = media_->to_sequence().get();
|
||||
return rescale_frame_number(s->getEndFrame(), s->frame_rate, fr);
|
||||
return rescale_frame_number(s->GetEndFrame(), s->frame_rate, fr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+12
-9
@@ -36,8 +36,8 @@
|
||||
#include "project/media.h"
|
||||
#include "project/footage.h"
|
||||
#include "rendering/framebufferobject.h"
|
||||
|
||||
#include "marker.h"
|
||||
#include "track.h"
|
||||
|
||||
struct ClipSpeed {
|
||||
ClipSpeed();
|
||||
@@ -47,16 +47,19 @@ struct ClipSpeed {
|
||||
|
||||
using ClipPtr = std::shared_ptr<Clip>;
|
||||
|
||||
class Sequence;
|
||||
|
||||
class Clip {
|
||||
public:
|
||||
Clip(Sequence *s);
|
||||
Clip(Track *s);
|
||||
~Clip();
|
||||
ClipPtr copy(Sequence *s);
|
||||
ClipPtr copy(Track *s);
|
||||
|
||||
void Save(QXmlStreamWriter& stream);
|
||||
|
||||
bool IsActiveAt(long timecode);
|
||||
bool IsSelected(bool containing = true);
|
||||
bool IsTransitionSelected(TransitionType type);
|
||||
|
||||
Track::Type type();
|
||||
|
||||
const QColor& color();
|
||||
void set_color(int r, int g, int b);
|
||||
@@ -91,8 +94,8 @@ public:
|
||||
long timeline_out(bool with_transition = false);
|
||||
void set_timeline_out(long t);
|
||||
|
||||
int track();
|
||||
void set_track(int t);
|
||||
Track* track();
|
||||
void set_track(Track* t);
|
||||
|
||||
bool reversed();
|
||||
void set_reversed(bool r);
|
||||
@@ -117,7 +120,7 @@ public:
|
||||
long length();
|
||||
|
||||
void refactor_frame_rate(ComboAction* ca, double multiplier, bool change_timeline_points);
|
||||
Sequence* sequence;
|
||||
Track* parent_;
|
||||
|
||||
// markers
|
||||
QVector<Marker>& get_markers();
|
||||
@@ -159,11 +162,11 @@ public:
|
||||
|
||||
private:
|
||||
// timeline variables (should be copied in copy())
|
||||
Track* track_;
|
||||
bool enabled_;
|
||||
long clip_in_;
|
||||
long timeline_in_;
|
||||
long timeline_out_;
|
||||
int track_;
|
||||
QString name_;
|
||||
Media* media_;
|
||||
int media_stream_;
|
||||
|
||||
+9
-1
@@ -32,7 +32,7 @@
|
||||
#include <QInputDialog>
|
||||
#include <QCoreApplication>
|
||||
|
||||
void draw_marker(QPainter &p, int x, int y, int bottom, bool selected) {
|
||||
void Marker::Draw(QPainter &p, int x, int y, int bottom, bool selected) {
|
||||
const QPoint points[5] = {
|
||||
QPoint(x, bottom),
|
||||
QPoint(x + MARKER_SIZE, bottom - MARKER_SIZE),
|
||||
@@ -126,3 +126,11 @@ void set_marker_internal(Sequence *seq) {
|
||||
|
||||
set_marker_internal(seq, clips);
|
||||
}
|
||||
|
||||
void Marker::Save(QXmlStreamWriter &stream) const
|
||||
{
|
||||
stream.writeStartElement("marker");
|
||||
stream.writeAttribute("frame", QString::number(frame));
|
||||
stream.writeAttribute("name", name);
|
||||
stream.writeEndElement();
|
||||
}
|
||||
|
||||
+4
-2
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <QString>
|
||||
#include <QPainter>
|
||||
#include <QXmlStreamWriter>
|
||||
#include <memory>
|
||||
|
||||
class Sequence;
|
||||
@@ -33,9 +34,10 @@ using SequencePtr = std::shared_ptr<Sequence>;
|
||||
struct Marker {
|
||||
long frame;
|
||||
QString name;
|
||||
};
|
||||
|
||||
void draw_marker(QPainter& p, int x, int y, int bottom, bool selected);
|
||||
void Save(QXmlStreamWriter& stream) const;
|
||||
static void Draw(QPainter& p, int x, int y, int bottom, bool selected);
|
||||
};
|
||||
|
||||
void set_marker_internal(Sequence *seq, const QVector<int>& clips);
|
||||
void set_marker_internal(Sequence* seq);
|
||||
|
||||
@@ -24,11 +24,9 @@
|
||||
struct Selection {
|
||||
long in;
|
||||
long out;
|
||||
int track;
|
||||
|
||||
long old_in;
|
||||
long old_out;
|
||||
int old_track;
|
||||
|
||||
bool trim_in;
|
||||
};
|
||||
|
||||
+79
-101
@@ -32,6 +32,12 @@ Sequence::Sequence() :
|
||||
workarea_out(0),
|
||||
wrapper_sequence(false)
|
||||
{
|
||||
// Set up tracks
|
||||
track_lists.resize(Track::kTypeCount);
|
||||
|
||||
for (int i=0;i<track_lists.size();i++) {
|
||||
track_lists[i] = std::make_shared<TrackList>(this, i);
|
||||
}
|
||||
}
|
||||
|
||||
SequencePtr Sequence::copy() {
|
||||
@@ -44,16 +50,8 @@ SequencePtr Sequence::copy() {
|
||||
s->audio_layout = audio_layout;
|
||||
|
||||
// deep copy all of the sequence's clips
|
||||
s->clips.resize(clips.size());
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
ClipPtr c = clips.at(i);
|
||||
if (c == nullptr) {
|
||||
s->clips[i] = nullptr;
|
||||
} else {
|
||||
ClipPtr copy = c->copy(s.get());
|
||||
copy->linked = c->linked;
|
||||
s->clips[i] = copy;
|
||||
}
|
||||
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,41 +60,91 @@ SequencePtr Sequence::copy() {
|
||||
return s;
|
||||
}
|
||||
|
||||
long Sequence::getEndFrame() {
|
||||
long end = 0;
|
||||
for (int j=0;j<clips.size();j++) {
|
||||
ClipPtr c = clips.at(j);
|
||||
if (c != nullptr && c->timeline_out() > end) {
|
||||
end = c->timeline_out();
|
||||
}
|
||||
void Sequence::Save(QXmlStreamWriter &stream)
|
||||
{
|
||||
stream.writeStartElement("sequence");
|
||||
stream.writeAttribute("id", QString::number(save_id));
|
||||
stream.writeAttribute("name", name);
|
||||
stream.writeAttribute("width", QString::number(width));
|
||||
stream.writeAttribute("height", QString::number(height));
|
||||
stream.writeAttribute("framerate", QString::number(frame_rate, 'f', 10));
|
||||
stream.writeAttribute("afreq", QString::number(audio_frequency));
|
||||
stream.writeAttribute("alayout", QString::number(audio_layout));
|
||||
if (this == olive::ActiveSequence.get()) {
|
||||
stream.writeAttribute("open", "1");
|
||||
}
|
||||
return end;
|
||||
stream.writeAttribute("workarea", QString::number(using_workarea));
|
||||
stream.writeAttribute("workareaIn", QString::number(workarea_in));
|
||||
stream.writeAttribute("workareaOut", QString::number(workarea_out));
|
||||
|
||||
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<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);
|
||||
}
|
||||
|
||||
return end_frame;
|
||||
}
|
||||
|
||||
QVector<Clip *> Sequence::GetAllClips()
|
||||
{
|
||||
QVector<Clip*> all_clips;
|
||||
|
||||
for (int i=0;i<tracks.size();i++) {
|
||||
all_clips.append(tracks.at(i)->GetAllClips());
|
||||
}
|
||||
|
||||
return all_clips;
|
||||
}
|
||||
|
||||
TrackList *Sequence::GetTrackList(Track::Type type)
|
||||
{
|
||||
return track_lists.at(type).get();
|
||||
}
|
||||
|
||||
void Sequence::Close()
|
||||
{
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
Clip* c = clips.at(i).get();
|
||||
if (c != nullptr) {
|
||||
c->Close(true);
|
||||
}
|
||||
QVector<Clip*> all_clips = GetAllClips();
|
||||
|
||||
for (int i=0;i<all_clips.size();i++) {
|
||||
all_clips.at(i)->Close(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Sequence::RefreshClips(Media *m) {
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
ClipPtr c = clips.at(i);
|
||||
void Sequence::RefreshClipsUsingMedia(Media *m) {
|
||||
|
||||
if (c != nullptr
|
||||
&& (m == nullptr || c->media() == m)) {
|
||||
QVector<Clip*> all_clips = GetAllClips();
|
||||
|
||||
for (int i=0;i<all_clips.size();i++) {
|
||||
Clip* c = all_clips.at(i);
|
||||
|
||||
if (m == nullptr || c->media() == m) {
|
||||
c->Close(true);
|
||||
c->refresh();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
QVector<Clip *> Sequence::SelectedClips(bool containing)
|
||||
{
|
||||
QVector<Clip*> all_clips = GetAllClips();
|
||||
|
||||
QVector<Clip*> selected_clips;
|
||||
|
||||
for (int i=0;i<clips.size();i++) {
|
||||
@@ -164,81 +212,11 @@ Effect *Sequence::GetSelectedGizmo()
|
||||
return gizmo_ptr;
|
||||
}
|
||||
|
||||
bool Sequence::IsClipSelected(int clip_index, bool containing)
|
||||
void Sequence::ClearSelections()
|
||||
{
|
||||
return IsClipSelected(clips.at(clip_index).get(), containing);
|
||||
}
|
||||
|
||||
bool Sequence::IsClipSelected(Clip *clip, bool containing)
|
||||
{
|
||||
for (int i=0;i<selections.size();i++) {
|
||||
const Selection& s = selections.at(i);
|
||||
if (clip->track() == s.track && ((clip->timeline_in() >= s.in && clip->timeline_out() <= s.out)
|
||||
|| (!containing && !(clip->timeline_in() < s.in && clip->timeline_out() < s.in)
|
||||
&& !(clip->timeline_in() > s.in && clip->timeline_out() > s.in)))) {
|
||||
return true;
|
||||
}
|
||||
for (int i=0;i<tracks.size();i++) {
|
||||
tracks.at(i)->ClearSelections();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Sequence::IsTransitionSelected(Transition *t)
|
||||
{
|
||||
if (t == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Clip* c = t->parent_clip;
|
||||
|
||||
int transition_track = t->parent_clip->track();
|
||||
long transition_in_point;
|
||||
long transition_out_point;
|
||||
|
||||
// Get positions of the transition on the timeline
|
||||
|
||||
if (t == c->opening_transition.get()) {
|
||||
transition_in_point = c->timeline_in();
|
||||
transition_out_point = c->timeline_in() + t->get_true_length();
|
||||
|
||||
if (t->secondary_clip != nullptr) {
|
||||
transition_in_point -= t->get_true_length();
|
||||
}
|
||||
} else {
|
||||
transition_in_point = c->timeline_out() - t->get_true_length();
|
||||
transition_out_point = c->timeline_out();
|
||||
|
||||
if (t->secondary_clip != nullptr) {
|
||||
transition_out_point += t->get_true_length();
|
||||
}
|
||||
}
|
||||
|
||||
// See if there's a selection matching this
|
||||
for (int i=0;i<selections.size();i++) {
|
||||
if (selections.at(i).in <= transition_in_point
|
||||
&& selections.at(i).out >= transition_out_point
|
||||
&& selections.at(i).track == transition_track) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Sequence::getTrackLimits(int* video_tracks, int* audio_tracks) {
|
||||
int vt = 0;
|
||||
int at = 0;
|
||||
for (int j=0;j<clips.size();j++) {
|
||||
ClipPtr c = clips.at(j);
|
||||
if (c != nullptr) {
|
||||
if (c->track() < 0 && c->track() < vt) { // video clip
|
||||
vt = c->track();
|
||||
} else if (c->track() > at) {
|
||||
at = c->track();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (video_tracks != nullptr) *video_tracks = vt;
|
||||
if (audio_tracks != nullptr) *audio_tracks = at;
|
||||
}
|
||||
|
||||
// static variable for the currently active sequence
|
||||
|
||||
+14
-7
@@ -27,21 +27,27 @@
|
||||
#include "clip.h"
|
||||
#include "marker.h"
|
||||
#include "selection.h"
|
||||
#include "tracklist.h"
|
||||
|
||||
class Sequence {
|
||||
class Sequence : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
Sequence();
|
||||
SequencePtr copy();
|
||||
|
||||
void Save(QXmlStreamWriter& stream);
|
||||
|
||||
QString name;
|
||||
void getTrackLimits(int* video_tracks, int* audio_tracks);
|
||||
long getEndFrame();
|
||||
int width;
|
||||
int height;
|
||||
double frame_rate;
|
||||
int audio_frequency;
|
||||
int audio_layout;
|
||||
|
||||
long GetEndFrame();
|
||||
QVector<Clip*> GetAllClips();
|
||||
TrackList* GetTrackList(Track::Type type);
|
||||
|
||||
/**
|
||||
* @brief Close all open clips in a Sequence
|
||||
*
|
||||
@@ -55,17 +61,17 @@ public:
|
||||
*/
|
||||
void Close();
|
||||
|
||||
void RefreshClips(Media* m = nullptr);
|
||||
void RefreshClipsUsingMedia(Media* m = nullptr);
|
||||
QVector<Clip*> SelectedClips(bool containing = true);
|
||||
QVector<int> SelectedClipIndexes();
|
||||
|
||||
Effect* GetSelectedGizmo();
|
||||
|
||||
bool IsClipSelected(int clip_index, bool containing = true);
|
||||
bool IsClipSelected(Clip* clip, bool containing = true);
|
||||
bool IsTransitionSelected(Transition* t);
|
||||
|
||||
QVector<Selection> selections;
|
||||
void ClearSelections();
|
||||
|
||||
long playhead;
|
||||
|
||||
bool using_workarea;
|
||||
@@ -77,7 +83,8 @@ public:
|
||||
int save_id;
|
||||
|
||||
QVector<Marker> markers;
|
||||
QVector<ClipPtr> clips;
|
||||
private:
|
||||
QVector<TrackList*> track_lists;
|
||||
};
|
||||
|
||||
using SequencePtr = std::shared_ptr<Sequence>;
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
#include "track.h"
|
||||
|
||||
#include "timeline/clip.h"
|
||||
|
||||
int olive::timeline::kTrackDefaultHeight = 40;
|
||||
int olive::timeline::kTrackMinHeight = 30;
|
||||
int olive::timeline::kTrackHeightIncrement = 10;
|
||||
|
||||
Track::Track(TrackList* parent, Type type) :
|
||||
parent_(parent),
|
||||
type_(type)
|
||||
{
|
||||
}
|
||||
|
||||
Track *Track::copy(TrackList *parent)
|
||||
{
|
||||
Track* t = new Track(parent, type_);
|
||||
|
||||
t->ResizeClipArray(ClipCount());
|
||||
for (int i=0;i<clips_.size();i++) {
|
||||
ClipPtr c = clips_.at(i);
|
||||
ClipPtr copy = c->copy(t);
|
||||
copy->linked = c->linked;
|
||||
t->clips_[i] = copy;
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
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.writeEndElement(); // clip
|
||||
}
|
||||
}
|
||||
|
||||
stream.writeEndElement(); // track
|
||||
}
|
||||
|
||||
Track::Type Track::type()
|
||||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
int Track::height()
|
||||
{
|
||||
return height_;
|
||||
}
|
||||
|
||||
void Track::set_height(int h)
|
||||
{
|
||||
height_ = h;
|
||||
}
|
||||
|
||||
void Track::AddClip(ClipPtr clip)
|
||||
{
|
||||
clips_.append(clip);
|
||||
if (clip->track() != nullptr) {
|
||||
clip->track()->RemoveClip(clip.get());
|
||||
}
|
||||
clip->set_track(this);
|
||||
}
|
||||
|
||||
void Track::RemoveClip(int i)
|
||||
{
|
||||
clips_.removeAt(i);
|
||||
}
|
||||
|
||||
void Track::RemoveClip(Clip *c)
|
||||
{
|
||||
for (int i=0;i<clips_.size();i++) {
|
||||
if (clips_.at(i).get() == c) {
|
||||
clips_.removeAt(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Track::ResizeClipArray(int new_size)
|
||||
{
|
||||
clips_.resize(new_size);
|
||||
}
|
||||
|
||||
QVector<ClipPtr> Track::GetAllClips()
|
||||
{
|
||||
return clips_;
|
||||
}
|
||||
|
||||
bool Track::IsClipSelected(int clip_index, bool containing)
|
||||
{
|
||||
return IsClipSelected(clips_.at(clip_index).get(), containing);
|
||||
}
|
||||
|
||||
bool Track::IsClipSelected(Clip *clip, bool containing)
|
||||
{
|
||||
for (int i=0;i<selections_.size();i++) {
|
||||
const Selection& s = selections_.at(i);
|
||||
if (((clip->timeline_in() >= s.in && clip->timeline_out() <= s.out)
|
||||
|| (!containing && !(clip->timeline_in() < s.in && clip->timeline_out() < s.in)
|
||||
&& !(clip->timeline_in() > s.in && clip->timeline_out() > s.in)))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Track::IsTransitionSelected(Transition *t)
|
||||
{
|
||||
if (t == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Clip* c = t->parent_clip;
|
||||
|
||||
long transition_in_point;
|
||||
long transition_out_point;
|
||||
|
||||
// Get positions of the transition on the timeline
|
||||
|
||||
if (t == c->opening_transition.get()) {
|
||||
transition_in_point = c->timeline_in();
|
||||
transition_out_point = c->timeline_in() + t->get_true_length();
|
||||
|
||||
if (t->secondary_clip != nullptr) {
|
||||
transition_in_point -= t->get_true_length();
|
||||
}
|
||||
} else {
|
||||
transition_in_point = c->timeline_out() - t->get_true_length();
|
||||
transition_out_point = c->timeline_out();
|
||||
|
||||
if (t->secondary_clip != nullptr) {
|
||||
transition_out_point += t->get_true_length();
|
||||
}
|
||||
}
|
||||
|
||||
// See if there's a selection matching this
|
||||
for (int i=0;i<selections_.size();i++) {
|
||||
const Selection& s = selections_.at(i);
|
||||
if (s.in <= transition_in_point
|
||||
&& s.out >= transition_out_point) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Track::ClearSelections()
|
||||
{
|
||||
selections_.clear();
|
||||
}
|
||||
|
||||
long Track::GetEndFrame()
|
||||
{
|
||||
long end_frame = 0;
|
||||
|
||||
for (int i=0;i<clips_.size();i++) {
|
||||
Clip* c = clips_.at(i).get();
|
||||
if (c != nullptr) {
|
||||
end_frame = qMax(end_frame, c->timeline_out(true));
|
||||
}
|
||||
}
|
||||
|
||||
return end_frame;
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#ifndef TRACK_H
|
||||
#define TRACK_H
|
||||
|
||||
#include <QVector>
|
||||
#include <memory>
|
||||
|
||||
#include "effects/effect.h"
|
||||
|
||||
namespace olive {
|
||||
namespace timeline {
|
||||
const int kGhostThickness = 2;
|
||||
const int kClipTextPadding = 3;
|
||||
|
||||
/**
|
||||
* @brief Set default track sizes
|
||||
*
|
||||
* Olive has a few default constants used for adjusting track heights in the Timeline. For HiDPI, it makes
|
||||
* sense to multiply these by the current DPI scale. It uses a variable from QApplication to do this multiplication,
|
||||
* which means the QApplication instance needs to be instantiated before these are calculated. Therefore, call this
|
||||
* function ONCE after QApplication is created to multiply the track heights correctly.
|
||||
*/
|
||||
void MultiplyTrackSizesByDPI();
|
||||
|
||||
extern int kTrackDefaultHeight;
|
||||
extern int kTrackMinHeight;
|
||||
extern int kTrackHeightIncrement;
|
||||
}
|
||||
}
|
||||
|
||||
class TrackList;
|
||||
|
||||
class Track : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Type {
|
||||
kTypeVideo,
|
||||
kTypeAudio,
|
||||
kTypeSubtitle,
|
||||
kTypeCount
|
||||
};
|
||||
|
||||
Track(TrackList* parent, Type type);
|
||||
Track* copy(TrackList* parent);
|
||||
|
||||
void Save(QXmlStreamWriter& stream);
|
||||
|
||||
Type type();
|
||||
|
||||
int height();
|
||||
void set_height(int h);
|
||||
|
||||
void AddClip(ClipPtr clip);
|
||||
int ClipCount();
|
||||
ClipPtr GetClip(int i);
|
||||
void RemoveClip(int i);
|
||||
void RemoveClip(Clip* c);
|
||||
QVector<ClipPtr> GetAllClips();
|
||||
QVector<Clip*> GetSelectedClips();
|
||||
|
||||
bool IsClipSelected(int clip_index, bool containing = true);
|
||||
bool IsClipSelected(Clip* clip, bool containing = true);
|
||||
bool IsTransitionSelected(Transition* t);
|
||||
|
||||
void ClearSelections();
|
||||
|
||||
long GetEndFrame();
|
||||
private:
|
||||
void ResizeClipArray(int new_size);
|
||||
|
||||
TrackList* parent_;
|
||||
Type type_;
|
||||
int height_;
|
||||
QVector<ClipPtr> clips_;
|
||||
QVector<EffectPtr> effects_;
|
||||
QVector<Selection> selections_;
|
||||
};
|
||||
|
||||
#endif // TRACK_H
|
||||
@@ -0,0 +1,50 @@
|
||||
#include "tracklist.h"
|
||||
|
||||
TrackList::TrackList(Sequence *parent, Track::Type type) :
|
||||
QObject(parent),
|
||||
type_(type)
|
||||
{
|
||||
// Ensure we have at least one track
|
||||
AddTrack();
|
||||
}
|
||||
|
||||
TrackListPtr TrackList::copy(Sequence *parent)
|
||||
{
|
||||
TrackListPtr t = std::make_shared<TrackList>(parent, type_);
|
||||
|
||||
t->ResizeTrackArray(tracks_.size());
|
||||
for (int i=0;i<tracks_.size();i++) {
|
||||
t->tracks_[i] = tracks_.at(i)->copy(t.get());
|
||||
}
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void TrackList::AddTrack()
|
||||
{
|
||||
TrackPtr track = std::make_shared<Track>(this, type_);
|
||||
tracks_.append(track);
|
||||
}
|
||||
|
||||
void TrackList::RemoveTrack(int i)
|
||||
{
|
||||
if (tracks_.size() == 1) {
|
||||
return;
|
||||
}
|
||||
tracks_.removeAt(i);
|
||||
}
|
||||
|
||||
Track *TrackList::First()
|
||||
{
|
||||
return tracks_.first().get();
|
||||
}
|
||||
|
||||
QVector<TrackPtr> TrackList::tracks()
|
||||
{
|
||||
return tracks_;
|
||||
}
|
||||
|
||||
Sequence *TrackList::GetParent()
|
||||
{
|
||||
return static_cast<Sequence*>(parent());
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef TRACKLIST_H
|
||||
#define TRACKLIST_H
|
||||
|
||||
#include "track.h"
|
||||
|
||||
class TrackList : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TrackList(Sequence* parent, Track::Type type);
|
||||
TrackList* copy(Sequence* parent);
|
||||
|
||||
void AddTrack();
|
||||
void RemoveTrack(int i);
|
||||
Track* First();
|
||||
QVector<Track*> tracks();
|
||||
|
||||
Sequence* GetParent();
|
||||
|
||||
|
||||
private:
|
||||
void ResizeTrackArray(int i);
|
||||
|
||||
Track::Type type_;
|
||||
QVector<Track*> tracks_;
|
||||
};
|
||||
|
||||
#endif // TRACKLIST_H
|
||||
+14
-20
@@ -58,6 +58,7 @@
|
||||
#include "global/debug.h"
|
||||
#include "effects/effect.h"
|
||||
#include "effects/internal/solideffect.h"
|
||||
#include "timeline/track.h"
|
||||
|
||||
#define MAX_TEXT_WIDTH 20
|
||||
#define TRANSITION_BETWEEN_RANGE 40
|
||||
@@ -123,7 +124,7 @@ void TimelineWidget::show_context_menu(const QPoint& pos) {
|
||||
bool audio_clips_are_selected = false;
|
||||
|
||||
for (int i=0;i<selected_clips.size();i++) {
|
||||
if (selected_clips.at(i)->track() < 0) {
|
||||
if (selected_clips.at(i)->type() == Track::kTypeVideo) {
|
||||
video_clips_are_selected = true;
|
||||
} else {
|
||||
audio_clips_are_selected = true;
|
||||
@@ -200,30 +201,22 @@ void TimelineWidget::toggle_autoscale() {
|
||||
}
|
||||
|
||||
void TimelineWidget::tooltip_timer_timeout() {
|
||||
if (olive::ActiveSequence != nullptr) {
|
||||
if (tooltip_clip < olive::ActiveSequence->clips.size()) {
|
||||
ClipPtr c = olive::ActiveSequence->clips.at(tooltip_clip);
|
||||
if (c != nullptr) {
|
||||
QToolTip::showText(QCursor::pos(),
|
||||
tr("%1\nStart: %2\nEnd: %3\nDuration: %4").arg(
|
||||
c->name(),
|
||||
frame_to_timecode(c->timeline_in(), olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate),
|
||||
frame_to_timecode(c->timeline_out(), olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate),
|
||||
frame_to_timecode(c->length(), olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate)
|
||||
));
|
||||
}
|
||||
}
|
||||
if (tooltip_clip != nullptr) {
|
||||
QToolTip::showText(QCursor::pos(),
|
||||
tr("%1\nStart: %2\nEnd: %3\nDuration: %4").arg(
|
||||
tooltip_clip->name(),
|
||||
frame_to_timecode(tooltip_clip->timeline_in(), olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate),
|
||||
frame_to_timecode(tooltip_clip->timeline_out(), olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate),
|
||||
frame_to_timecode(tooltip_clip->length(), olive::CurrentConfig.timecode_view, olive::ActiveSequence->frame_rate)
|
||||
));
|
||||
}
|
||||
|
||||
tooltip_timer.stop();
|
||||
}
|
||||
|
||||
void TimelineWidget::open_sequence_properties() {
|
||||
QList<Media*> sequence_items;
|
||||
QList<Media*> all_top_level_items;
|
||||
for (int i=0;i<olive::project_model.childCount();i++) {
|
||||
all_top_level_items.append(olive::project_model.child(i));
|
||||
}
|
||||
panel_project->get_all_media_from_table(all_top_level_items, sequence_items, MEDIA_TYPE_SEQUENCE); // find all sequences in project
|
||||
QVector<Media*> sequence_items = olive::project_model.GetAllSequences();
|
||||
|
||||
for (int i=0;i<sequence_items.size();i++) {
|
||||
if (sequence_items.at(i)->to_sequence() == olive::ActiveSequence) {
|
||||
NewSequenceDialog nsd(this, sequence_items.at(i));
|
||||
@@ -231,6 +224,7 @@ void TimelineWidget::open_sequence_properties() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QMessageBox::critical(this, tr("Error"), tr("Couldn't locate media wrapper for sequence."));
|
||||
}
|
||||
|
||||
|
||||
+5
-7
@@ -37,18 +37,16 @@
|
||||
|
||||
class Timeline;
|
||||
|
||||
struct TimelineTrackHeight {
|
||||
int index;
|
||||
int height;
|
||||
};
|
||||
|
||||
bool same_sign(int a, int b);
|
||||
void draw_waveform(ClipPtr clip, const FootageStream *ms, long media_length, QPainter* p, const QRect& clip_rect, int waveform_start, int waveform_limit, double zoom);
|
||||
|
||||
class TimelineWidget : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit TimelineWidget(QWidget *parent = 0);
|
||||
explicit TimelineWidget(QWidget *parent);
|
||||
|
||||
void SetTracks(QVector<Track>& tracks);
|
||||
|
||||
QScrollBar* scrollBar;
|
||||
bool bottom_align;
|
||||
|
||||
@@ -92,7 +90,7 @@ private:
|
||||
SequencePtr self_created_sequence;
|
||||
|
||||
QTimer tooltip_timer;
|
||||
int tooltip_clip;
|
||||
Clip* tooltip_clip;
|
||||
|
||||
int scroll;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user