From 114606c28e517d3ae287219f18586c639a87cd9d Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Sat, 30 Mar 2019 03:09:43 +1100 Subject: [PATCH] rewrite work continued --- olive.pro | 8 +- panels/effectcontrols.cpp | 4 +- panels/project.cpp | 189 ++++++-------------------------------- panels/project.h | 2 - panels/timeline.cpp | 8 +- panels/timeline.h | 25 ----- panels/viewer.cpp | 45 +++++---- panels/viewer.h | 4 +- project/media.cpp | 2 +- project/projectmodel.cpp | 40 +++++++- project/projectmodel.h | 7 ++ rendering/cacher.cpp | 2 +- timeline/clip.cpp | 136 ++++++++++++++++++++++----- timeline/clip.h | 21 +++-- timeline/marker.cpp | 10 +- timeline/marker.h | 6 +- timeline/selection.h | 2 - timeline/sequence.cpp | 180 ++++++++++++++++-------------------- timeline/sequence.h | 21 +++-- timeline/track.cpp | 174 +++++++++++++++++++++++++++++++++++ timeline/track.h | 79 ++++++++++++++++ timeline/tracklist.cpp | 50 ++++++++++ timeline/tracklist.h | 28 ++++++ ui/timelinewidget.cpp | 34 +++---- ui/timelinewidget.h | 12 +-- 25 files changed, 692 insertions(+), 397 deletions(-) create mode 100644 timeline/track.cpp create mode 100644 timeline/track.h create mode 100644 timeline/tracklist.cpp create mode 100644 timeline/tracklist.h diff --git a/olive.pro b/olive.pro index a47ec0107..cdff79126 100644 --- a/olive.pro +++ b/olive.pro @@ -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 += diff --git a/panels/effectcontrols.cpp b/panels/effectcontrols.cpp index 454ffd884..49a45db7b 100644 --- a/panels/effectcontrols.cpp +++ b/panels/effectcontrols.cpp @@ -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()); } diff --git a/panels/project.cpp b/panels/project.cpp index 697265aa9..c75a1ab35 100644 --- a/panels/project.cpp +++ b/panels/project.cpp @@ -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& items, QList& list, int search_type) { - for (int i=0;iget_type() == MEDIA_TYPE_FOLDER) { - QList children; - for (int j=0;jchildCount();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 parents; - QList sequence_items; - QList all_top_level_items; - for (int i=0;i 0) { + QVector all_sequences = olive::project_model.GetAllSequences(); + if (all_sequences.size() > 0) { - QList media_items; - get_all_media_from_table(items, media_items, MEDIA_TYPE_FOOTAGE); + QVector all_footage = olive::project_model.GetAllFootage(); - for (int i=0;ito_footage(); bool confirm_delete = false; - for (int j=0;jto_sequence().get(); - for (int k=0;kclips.size();k++) { - ClipPtr c = s->clips.at(k); + for (int j=0;jto_sequence().get(); + QVector sequence_clips = s->GetAllClips(); + + for (int k=0;kmedia() == 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;mset_media(nullptr); } } else if (items.at(i)->get_type() == MEDIA_TYPE_FOOTAGE) { - if (panel_footage_viewer->seq != nullptr) { - for (int j=0;jseq->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;iclips.size();i++) { - const ClipPtr& c = olive::ActiveSequence->clips.at(i); + QVector sequence_clips = olive::ActiveSequence->GetAllClips(); + for (int i=0;iupdate(); } -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;imarkers.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 transition_save_cache; - QVector transition_clip_save_cache; - - for (int j=0;jclips.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;kget_markers().size();k++) { - save_marker(stream, c->get_markers().at(k)); - } - } - - // save clip links - stream.writeStartElement("linked"); // linked - for (int k=0;klinked.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;keffects.size();k++) { - stream.writeStartElement("effect"); // effect - c->effects.at(k)->save(stream); - stream.writeEndElement(); // effect - } - - stream.writeEndElement(); // clip - } - } - for (int j=0;jmarkers.size();j++) { - save_marker(stream, s->markers.at(j)); - } - stream.writeEndElement(); + s->Save(stream); } } } diff --git a/panels/project.h b/panels/project.h index f8ea096f2..7d959a3e4 100644 --- a/panels/project.h +++ b/panels/project.h @@ -81,8 +81,6 @@ public: QModelIndexList get_current_selected(); - void get_all_media_from_table(QList &items, QList &list, int type = -1); - bool IsToolbarVisible(); bool IsProjectWidget(QObject *child); diff --git a/panels/timeline.cpp b/panels/timeline.cpp index a6ff725bc..390b10553 100644 --- a/panels/timeline.cpp +++ b/panels/timeline.cpp @@ -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) { diff --git a/panels/timeline.h b/panels/timeline.h index 4dfb2cb1e..f1ce05260 100644 --- a/panels/timeline.h +++ b/panels/timeline.h @@ -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 track_heights; - QWidget* timeline_area; TimelineWidget* video_area; TimelineWidget* audio_area; diff --git a/panels/viewer.cpp b/panels/viewer.cpp index e824ff347..fd60fd994 100644 --- a/panels/viewer.cpp +++ b/panels/viewer.cpp @@ -127,12 +127,15 @@ void Viewer::reset_all_audio() { // reset all clip audio if (seq != nullptr) { long last_frame = 0; - for (int i=0;iclips.size();i++) { - ClipPtr c = seq->clips.at(i); - if (c != nullptr) { - c->reset_audio(); - last_frame = qMax(last_frame, c->timeline_out()); - } + + QVector all_clips = seq->GetAllClips(); + for (int i=0;ireset_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(); } diff --git a/panels/viewer.h b/panels/viewer.h index f6bb29f1e..e488a9696 100644 --- a/panels/viewer.h +++ b/panels/viewer.h @@ -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); diff --git a/project/media.cpp b/project/media.cpp index 7a908f7ef..53914a4c5 100644 --- a/project/media.cpp +++ b/project/media.cpp @@ -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(); diff --git a/project/projectmodel.cpp b/project/projectmodel.cpp index 7903ad89d..57099ac35 100644 --- a/project/projectmodel.cpp +++ b/project/projectmodel.cpp @@ -50,7 +50,7 @@ void ProjectModel::destroy_root() { panel_footage_viewer->set_media(nullptr); } - root_item_ = std::make_shared(); + root_item_ = nullptr; } void ProjectModel::clear() { @@ -196,6 +196,44 @@ void ProjectModel::set_icon(Media* m, const QIcon &ico) { emit dataChanged(index, index); } +QVector ProjectModel::GetAllSequences() +{ + return GetAllMediaOfType(MEDIA_TYPE_SEQUENCE); +} + +QVector ProjectModel::GetAllFootage() +{ + return GetAllMediaOfType(MEDIA_TYPE_FOOTAGE); +} + +QVector ProjectModel::GetAllFolders() +{ + return GetAllMediaOfType(MEDIA_TYPE_FOLDER); +} + +QVector ProjectModel::GetAllMediaOfType(int search_type) +{ + QVector media_list; + RecurseTree(root_item_.get(), media_list, search_type); + return media_list; +} + +void ProjectModel::RecurseTree(Media* parent, QVector& list, int search_type) +{ + for (int i=0;ichildCount();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; diff --git a/project/projectmodel.h b/project/projectmodel.h index 59c6f5b6d..282d17625 100644 --- a/project/projectmodel.h +++ b/project/projectmodel.h @@ -58,8 +58,15 @@ public: int childCount(Media* parent = nullptr); void set_icon(Media* m, const QIcon &ico); + QVector GetAllSequences(); + QVector GetAllFootage(); + QVector GetAllFolders(); + private: MediaPtr root_item_; + + QVector GetAllMediaOfType(int search_type); + void RecurseTree(Media* parent, QVector &list, int search_type); }; namespace olive { diff --git a/rendering/cacher.cpp b/rendering/cacher.cpp index 5a58744d9..f85cf15a4 100644 --- a/rendering/cacher.cpp +++ b/rendering/cacher.cpp @@ -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; diff --git a/timeline/clip.cpp b/timeline/clip.cpp index b90b9be84..c7b33e13e 100644 --- a/timeline/clip.cpp +++ b/timeline/clip.cpp @@ -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(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 -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;ksave(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); } } } diff --git a/timeline/clip.h b/timeline/clip.h index 1dae4828d..eb3fccbf7 100644 --- a/timeline/clip.h +++ b/timeline/clip.h @@ -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; -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& 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_; diff --git a/timeline/marker.cpp b/timeline/marker.cpp index c816cf10c..18fa068b9 100644 --- a/timeline/marker.cpp +++ b/timeline/marker.cpp @@ -32,7 +32,7 @@ #include #include -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(); +} diff --git a/timeline/marker.h b/timeline/marker.h index f9226f00b..9e88bf598 100644 --- a/timeline/marker.h +++ b/timeline/marker.h @@ -25,6 +25,7 @@ #include #include +#include #include class Sequence; @@ -33,9 +34,10 @@ using SequencePtr = std::shared_ptr; 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& clips); void set_marker_internal(Sequence* seq); diff --git a/timeline/selection.h b/timeline/selection.h index eaa67372b..3f66905f8 100644 --- a/timeline/selection.h +++ b/timeline/selection.h @@ -24,11 +24,9 @@ struct Selection { long in; long out; - int track; long old_in; long old_out; - int old_track; bool trim_in; }; diff --git a/timeline/sequence.cpp b/timeline/sequence.cpp index 8d3b06ecb..ae474e07d 100644 --- a/timeline/sequence.cpp +++ b/timeline/sequence.cpp @@ -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(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;iclips[i] = nullptr; - } else { - ClipPtr copy = c->copy(s.get()); - copy->linked = c->linked; - s->clips[i] = copy; - } + for (int i=0;itrack_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;jtimeline_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 transition_save_cache; + QVector transition_clip_save_cache; + + for (int j=0;jSave(stream); + } + + + for (int j=0;jGetEndFrame(), end_frame); + } + + return end_frame; +} + +QVector Sequence::GetAllClips() +{ + QVector all_clips; + + for (int i=0;iGetAllClips()); + } + + return all_clips; +} + +TrackList *Sequence::GetTrackList(Track::Type type) +{ + return track_lists.at(type).get(); } void Sequence::Close() { - for (int i=0;iClose(true); - } + QVector all_clips = GetAllClips(); + + for (int i=0;iClose(true); } } -void Sequence::RefreshClips(Media *m) { - for (int i=0;imedia() == m)) { + QVector all_clips = GetAllClips(); + + for (int i=0;imedia() == m) { c->Close(true); c->refresh(); } } + } QVector Sequence::SelectedClips(bool containing) { + QVector all_clips = GetAllClips(); + QVector selected_clips; for (int i=0;itrack() == 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;iClearSelections(); } - 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= 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;jtrack() < 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 diff --git a/timeline/sequence.h b/timeline/sequence.h index 901d37428..0998858ef 100644 --- a/timeline/sequence.h +++ b/timeline/sequence.h @@ -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 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 SelectedClips(bool containing = true); QVector SelectedClipIndexes(); Effect* GetSelectedGizmo(); - bool IsClipSelected(int clip_index, bool containing = true); bool IsClipSelected(Clip* clip, bool containing = true); bool IsTransitionSelected(Transition* t); - QVector selections; + void ClearSelections(); + long playhead; bool using_workarea; @@ -77,7 +83,8 @@ public: int save_id; QVector markers; - QVector clips; +private: + QVector track_lists; }; using SequencePtr = std::shared_ptr; diff --git a/timeline/track.cpp b/timeline/track.cpp new file mode 100644 index 000000000..2b6d4d52f --- /dev/null +++ b/timeline/track.cpp @@ -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;icopy(t); + copy->linked = c->linked; + t->clips_[i] = copy; + } + + return t; +} + +void Track::Save(QXmlStreamWriter &stream) +{ + stream.writeStartElement("track"); + + for (int j=0;jSave(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 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;itimeline_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= transition_out_point) { + return true; + } + } + + return false; +} + +void Track::ClearSelections() +{ + selections_.clear(); +} + +long Track::GetEndFrame() +{ + long end_frame = 0; + + for (int i=0;itimeline_out(true)); + } + } + + return end_frame; +} diff --git a/timeline/track.h b/timeline/track.h new file mode 100644 index 000000000..43d90735e --- /dev/null +++ b/timeline/track.h @@ -0,0 +1,79 @@ +#ifndef TRACK_H +#define TRACK_H + +#include +#include + +#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 GetAllClips(); + QVector 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 clips_; + QVector effects_; + QVector selections_; +}; + +#endif // TRACK_H diff --git a/timeline/tracklist.cpp b/timeline/tracklist.cpp new file mode 100644 index 000000000..1f4bcf469 --- /dev/null +++ b/timeline/tracklist.cpp @@ -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(parent, type_); + + t->ResizeTrackArray(tracks_.size()); + for (int i=0;itracks_[i] = tracks_.at(i)->copy(t.get()); + } + + return t; +} + +void TrackList::AddTrack() +{ + TrackPtr track = std::make_shared(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 TrackList::tracks() +{ + return tracks_; +} + +Sequence *TrackList::GetParent() +{ + return static_cast(parent()); +} diff --git a/timeline/tracklist.h b/timeline/tracklist.h new file mode 100644 index 000000000..599a76bf3 --- /dev/null +++ b/timeline/tracklist.h @@ -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 tracks(); + + Sequence* GetParent(); + + +private: + void ResizeTrackArray(int i); + + Track::Type type_; + QVector tracks_; +}; + +#endif // TRACKLIST_H diff --git a/ui/timelinewidget.cpp b/ui/timelinewidget.cpp index e6e90fa58..7e1873ca7 100644 --- a/ui/timelinewidget.cpp +++ b/ui/timelinewidget.cpp @@ -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;itrack() < 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 sequence_items; - QList all_top_level_items; - for (int i=0;iget_all_media_from_table(all_top_level_items, sequence_items, MEDIA_TYPE_SEQUENCE); // find all sequences in project + QVector sequence_items = olive::project_model.GetAllSequences(); + for (int i=0;ito_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.")); } diff --git a/ui/timelinewidget.h b/ui/timelinewidget.h index 0a8f55527..bb61279fc 100644 --- a/ui/timelinewidget.h +++ b/ui/timelinewidget.h @@ -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& 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;