From e9f5d0d2486e0a01cf7ce75be1eba20219990e6c Mon Sep 17 00:00:00 2001 From: itsmattkc Date: Fri, 11 Oct 2019 16:57:12 +1100 Subject: [PATCH] work towards shifting functions from timelineview to timelinewidget --- app/CMakeLists.txt | 1 + app/node/output/timeline/CMakeLists.txt | 1 + app/node/output/timeline/timeline.cpp | 14 +- app/node/output/timeline/timeline.h | 7 + app/timeline/CMakeLists.txt | 24 ++ .../timelinecoordinate.cpp | 14 +- .../timelinecoordinate.h | 10 +- app/timeline/trackreference.cpp | 48 +++ app/timeline/trackreference.h | 45 +++ app/widget/timelineview/CMakeLists.txt | 2 - .../timelineview/timelinescaledobject.cpp | 27 +- .../timelineview/timelinescaledobject.h | 11 +- app/widget/timelineview/timelineview.cpp | 270 +++-------------- app/widget/timelineview/timelineview.h | 279 +----------------- .../timelineview/timelineviewblockitem.cpp | 4 +- .../timelineview/timelineviewenditem.cpp | 2 +- .../timelineview/timelineviewghostitem.cpp | 8 +- .../timelineview/timelineviewghostitem.h | 4 +- .../timelineview/timelineviewmouseevent.cpp | 2 +- .../timelineview/timelineviewmouseevent.h | 4 +- app/widget/timelineview/timelineviewrect.cpp | 4 +- app/widget/timelineview/timelineviewrect.h | 7 +- app/widget/timelineview/tool/hand.cpp | 6 +- app/widget/timelineview/tool/import.cpp | 91 ++++-- app/widget/timelineview/tool/pointer.cpp | 71 +++-- app/widget/timelineview/tool/razor.cpp | 16 +- app/widget/timelineview/tool/ripple.cpp | 16 +- app/widget/timelineview/tool/rolling.cpp | 20 +- app/widget/timelineview/tool/slide.cpp | 12 +- app/widget/timelineview/tool/slip.cpp | 12 +- app/widget/timelineview/tool/tool.cpp | 56 ++-- app/widget/timelineview/tool/zoom.cpp | 25 +- app/widget/timelinewidget/timelinewidget.cpp | 212 +++++++++++-- app/widget/timelinewidget/timelinewidget.h | 274 ++++++++++++++++- 34 files changed, 895 insertions(+), 704 deletions(-) create mode 100644 app/timeline/CMakeLists.txt rename app/{widget/timelineview => timeline}/timelinecoordinate.cpp (75%) rename app/{widget/timelineview => timeline}/timelinecoordinate.h (76%) create mode 100644 app/timeline/trackreference.cpp create mode 100644 app/timeline/trackreference.h diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt index 48d7c6438..60b0cceb9 100644 --- a/app/CMakeLists.txt +++ b/app/CMakeLists.txt @@ -31,6 +31,7 @@ add_subdirectory(panel) add_subdirectory(project) add_subdirectory(render) add_subdirectory(task) +add_subdirectory(timeline) add_subdirectory(tool) add_subdirectory(ui) add_subdirectory(undo) diff --git a/app/node/output/timeline/CMakeLists.txt b/app/node/output/timeline/CMakeLists.txt index c37d1a788..6b7989f64 100644 --- a/app/node/output/timeline/CMakeLists.txt +++ b/app/node/output/timeline/CMakeLists.txt @@ -20,5 +20,6 @@ set(OLIVE_SOURCES node/output/timeline/timeline.cpp node/output/timeline/tracklist.h node/output/timeline/tracklist.cpp + node/output/timeline/tracktypes.h PARENT_SCOPE ) diff --git a/app/node/output/timeline/timeline.cpp b/app/node/output/timeline/timeline.cpp index ffdbdcf75..7f0933ac0 100644 --- a/app/node/output/timeline/timeline.cpp +++ b/app/node/output/timeline/timeline.cpp @@ -37,12 +37,14 @@ TimelineOutput::TimelineOutput() NodeInput* track_input = new NodeInput(QString("track_in_%1").arg(i)); track_input->add_data_input(NodeParam::kTrack); AddParameter(track_input); - track_inputs_[i] = track_input; + track_inputs_.replace(i, track_input); TrackList* list = new TrackList(this, static_cast(i), track_input); - track_lists_[i] = list; + track_lists_.replace(i, list); connect(list, SIGNAL(TrackListChanged()), this, SLOT(UpdateTrackCache())); connect(list, SIGNAL(LengthChanged(const rational &)), this, SLOT(UpdateLength(const rational &))); + connect(list, SIGNAL(BlockAdded(Block*, int)), this, SLOT(TrackListAddedBlock(Block*, int))); + connect(list, SIGNAL(BlockRemoved(Block*)), this, SIGNAL(BlockRemoved(Block*))); } length_output_ = new NodeOutput("length_out"); @@ -107,8 +109,6 @@ void TimelineOutput::UpdateTrackCache() void TimelineOutput::UpdateLength(const rational &length) { - qDebug() << "Updating length! Received value:" << length; - // If this length is equal, no-op if (length == length_) { return; @@ -150,3 +150,9 @@ TrackList *TimelineOutput::track_list(TrackType type) { return track_lists_.at(type); } + +void TimelineOutput::TrackListAddedBlock(Block *block, int index) +{ + TrackType type = static_cast(sender())->TrackType(); + emit BlockAdded(block, TrackReference(type, index)); +} diff --git a/app/node/output/timeline/timeline.h b/app/node/output/timeline/timeline.h index ff233bd11..84ed3317b 100644 --- a/app/node/output/timeline/timeline.h +++ b/app/node/output/timeline/timeline.h @@ -24,6 +24,7 @@ #include "common/timelinecommon.h" #include "node/block/block.h" #include "node/output/track/track.h" +#include "timeline/trackreference.h" #include "tracklist.h" #include "tracktypes.h" @@ -56,6 +57,10 @@ public: signals: void LengthChanged(const rational& length); + void BlockAdded(Block* block, TrackReference track); + + void BlockRemoved(Block* block); + protected: virtual QVariant Value(NodeOutput* output, const rational& time) override; @@ -75,6 +80,8 @@ private slots: void UpdateLength(const rational &length); + void TrackListAddedBlock(Block* block, int index); + }; #endif // TIMELINEOUTPUT_H diff --git a/app/timeline/CMakeLists.txt b/app/timeline/CMakeLists.txt new file mode 100644 index 000000000..c0bd69c9f --- /dev/null +++ b/app/timeline/CMakeLists.txt @@ -0,0 +1,24 @@ +# Olive - Non-Linear Video Editor +# Copyright (C) 2019 Olive Team +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +set(OLIVE_SOURCES + ${OLIVE_SOURCES} + timeline/timelinecoordinate.h + timeline/timelinecoordinate.cpp + timeline/trackreference.h + timeline/trackreference.cpp + PARENT_SCOPE +) diff --git a/app/widget/timelineview/timelinecoordinate.cpp b/app/timeline/timelinecoordinate.cpp similarity index 75% rename from app/widget/timelineview/timelinecoordinate.cpp rename to app/timeline/timelinecoordinate.cpp index 8a41d84f5..d25422cab 100644 --- a/app/widget/timelineview/timelinecoordinate.cpp +++ b/app/timeline/timelinecoordinate.cpp @@ -21,22 +21,28 @@ #include "timelinecoordinate.h" TimelineCoordinate::TimelineCoordinate() : - track_(0) + track_(kTrackTypeNone, 0) { } -TimelineCoordinate::TimelineCoordinate(const rational &frame, const int &track) : +TimelineCoordinate::TimelineCoordinate(const rational &frame, const TrackReference &track) : frame_(frame), track_(track) { } +TimelineCoordinate::TimelineCoordinate(const rational &frame, const TrackType &track_type, const int &track_index) : + frame_(frame), + track_(track_type, track_index) +{ +} + const rational &TimelineCoordinate::GetFrame() const { return frame_; } -const int &TimelineCoordinate::GetTrack() const +const TrackReference &TimelineCoordinate::GetTrack() const { return track_; } @@ -46,7 +52,7 @@ void TimelineCoordinate::SetFrame(const rational &frame) frame_ = frame; } -void TimelineCoordinate::SetTrack(const int &track) +void TimelineCoordinate::SetTrack(const TrackReference &track) { track_ = track; } diff --git a/app/widget/timelineview/timelinecoordinate.h b/app/timeline/timelinecoordinate.h similarity index 76% rename from app/widget/timelineview/timelinecoordinate.h rename to app/timeline/timelinecoordinate.h index 605135684..00c3161c6 100644 --- a/app/widget/timelineview/timelinecoordinate.h +++ b/app/timeline/timelinecoordinate.h @@ -22,23 +22,25 @@ #define TIMELINECOORDINATE_H #include "common/rational.h" +#include "trackreference.h" class TimelineCoordinate { public: TimelineCoordinate(); - TimelineCoordinate(const rational& frame, const int& track); + TimelineCoordinate(const rational& frame, const TrackReference& track); + TimelineCoordinate(const rational& frame, const TrackType& track_type, const int& track_index); const rational& GetFrame() const; - const int& GetTrack() const; + const TrackReference& GetTrack() const; void SetFrame(const rational& frame); - void SetTrack(const int& track); + void SetTrack(const TrackReference& track); private: rational frame_; - int track_; + TrackReference track_; }; diff --git a/app/timeline/trackreference.cpp b/app/timeline/trackreference.cpp new file mode 100644 index 000000000..3303d38db --- /dev/null +++ b/app/timeline/trackreference.cpp @@ -0,0 +1,48 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#include "trackreference.h" + +TrackReference::TrackReference() : + type_(kTrackTypeNone), + index_(0) +{ +} + +TrackReference::TrackReference(const TrackType &type, const int &index) : + type_(type), + index_(index) +{ +} + +const TrackType &TrackReference::type() const +{ + return type_; +} + +const int &TrackReference::index() const +{ + return index_; +} + +bool TrackReference::operator==(const TrackReference &ref) const +{ + return type_ == ref.type_ && index_ == ref.index_; +} diff --git a/app/timeline/trackreference.h b/app/timeline/trackreference.h new file mode 100644 index 000000000..675c7fb51 --- /dev/null +++ b/app/timeline/trackreference.h @@ -0,0 +1,45 @@ +/*** + + Olive - Non-Linear Video Editor + Copyright (C) 2019 Olive Team + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +***/ + +#ifndef TRACKREFERENCE_H +#define TRACKREFERENCE_H + +#include "node/output/timeline/tracktypes.h" + +class TrackReference +{ +public: + TrackReference(); + + TrackReference(const TrackType& type, const int& index); + + const TrackType& type() const; + + const int& index() const; + + bool operator==(const TrackReference& ref) const; + +private: + TrackType type_; + + int index_; +}; + +#endif // TRACKREFERENCE_H diff --git a/app/widget/timelineview/CMakeLists.txt b/app/widget/timelineview/CMakeLists.txt index 515a529bf..2eb9e609f 100644 --- a/app/widget/timelineview/CMakeLists.txt +++ b/app/widget/timelineview/CMakeLists.txt @@ -19,8 +19,6 @@ add_subdirectory(undo) set(OLIVE_SOURCES ${OLIVE_SOURCES} - widget/timelineview/timelinecoordinate.h - widget/timelineview/timelinecoordinate.cpp widget/timelineview/timelineplayhead.h widget/timelineview/timelineplayhead.cpp widget/timelineview/timelinescaledobject.h diff --git a/app/widget/timelineview/timelinescaledobject.cpp b/app/widget/timelineview/timelinescaledobject.cpp index b0d4fc264..4f17523b0 100644 --- a/app/widget/timelineview/timelinescaledobject.cpp +++ b/app/widget/timelineview/timelinescaledobject.cpp @@ -6,7 +6,32 @@ TimelineScaledObject::TimelineScaledObject() : } -double TimelineScaledObject::TimeToScreenCoord(const rational &time) +const rational &TimelineScaledObject::timebase() +{ + return timebase_; +} + +const double &TimelineScaledObject::timebase_dbl() +{ + return timebase_dbl_; +} + +double TimelineScaledObject::TimeToScene(const rational &time) { return time.toDouble() * scale_; } + +rational TimelineScaledObject::SceneToTime(const double &x) +{ + // Adjust screen point by scale and timebase + qint64 scaled_x_mvmt = qRound64(x / scale_ / timebase_dbl_); + + // Return a time in the timebase + return rational(scaled_x_mvmt * timebase_.numerator(), timebase_.denominator()); +} + +void TimelineScaledObject::SetTimebaseInternal(const rational &timebase) +{ + timebase_ = timebase; + timebase_dbl_ = timebase_.toDouble(); +} diff --git a/app/widget/timelineview/timelinescaledobject.h b/app/widget/timelineview/timelinescaledobject.h index c915ad511..6f06e25e5 100644 --- a/app/widget/timelineview/timelinescaledobject.h +++ b/app/widget/timelineview/timelinescaledobject.h @@ -8,13 +8,22 @@ class TimelineScaledObject public: TimelineScaledObject(); + const rational& timebase(); + const double& timebase_dbl(); + protected: - double TimeToScreenCoord(const rational& time); + double TimeToScene(const rational& time); + rational SceneToTime(const double &x); + + void SetTimebaseInternal(const rational& timebase); double scale_; private: + rational timebase_; + + double timebase_dbl_; }; #endif // TIMELINESCALEDOBJECT_H diff --git a/app/widget/timelineview/timelineview.cpp b/app/widget/timelineview/timelineview.cpp index 00fbefa87..4deecdc2e 100644 --- a/app/widget/timelineview/timelineview.cpp +++ b/app/widget/timelineview/timelineview.cpp @@ -32,7 +32,6 @@ #include "core.h" #include "node/input/media/media.h" #include "project/item/footage/footage.h" -#include "tool/tool.h" TimelineView::TimelineView(Qt::Alignment vertical_alignment, QWidget *parent) : QGraphicsView(parent), @@ -48,25 +47,6 @@ TimelineView::TimelineView(Qt::Alignment vertical_alignment, QWidget *parent) : setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn); setBackgroundRole(QPalette::Window); - // Create tools - tools_.resize(olive::tool::kCount); - tools_.fill(nullptr); - - tools_.replace(olive::tool::kPointer, std::make_shared(this)); - // tools_.replace(olive::tool::kEdit, new PointerTool(this)); FIXME: Implement - tools_.replace(olive::tool::kRipple, std::make_shared(this)); - tools_.replace(olive::tool::kRolling, std::make_shared(this)); - tools_.replace(olive::tool::kRazor, std::make_shared(this)); - tools_.replace(olive::tool::kSlip, std::make_shared(this)); - tools_.replace(olive::tool::kSlide, std::make_shared(this)); - tools_.replace(olive::tool::kHand, std::make_shared(this)); - tools_.replace(olive::tool::kZoom, std::make_shared(this)); - //tools_.replace(olive::tool::kTransition, new (this)); FIXME: Implement - //tools_.replace(olive::tool::kRecord, new PointerTool(this)); FIXME: Implement - //tools_.replace(olive::tool::kAdd, new PointerTool(this)); FIXME: Implement - - import_tool_ = std::make_shared(this); - connect(&scene_, SIGNAL(changed(const QList&)), this, SLOT(UpdateSceneRect())); // Create end item @@ -77,43 +57,6 @@ TimelineView::TimelineView(Qt::Alignment vertical_alignment, QWidget *parent) : SetScale(1.0); } -void TimelineView::AddBlock(Block *block, int track) -{ - switch (block->type()) { - case Block::kClip: - case Block::kGap: - { - TimelineViewBlockItem* item = new TimelineViewBlockItem(); - - // Set up clip with view parameters (clip item will automatically size its rect accordingly) - item->SetBlock(block); - item->SetY(GetTrackY(track)); - item->SetHeight(GetTrackHeight(track)); - item->SetScale(scale_); - item->SetTrack(track); - - // Add to list of clip items that can be iterated through - block_items_.insert(block, item); - - // Add item to graphics scene - scene_.addItem(item); - - connect(block, SIGNAL(Refreshed()), this, SLOT(BlockChanged())); - break; - } - case Block::kEnd: - // Do nothing - break; - } -} - -void TimelineView::RemoveBlock(Block *block) -{ - delete block_items_[block]; - - block_items_.remove(block); -} - void TimelineView::AddTrack(TrackOutput *track) { foreach (Block* b, track->Blocks()) { @@ -132,20 +75,6 @@ void TimelineView::SetScale(const double &scale) { scale_ = scale; - QMapIterator iterator(block_items_); - - while (iterator.hasNext()) { - iterator.next(); - - if (iterator.value() != nullptr) { - iterator.value()->SetScale(scale_); - } - } - - foreach (TimelineViewGhostItem* ghost, ghost_items_) { - ghost->SetScale(scale_); - } - // Force redraw for playhead viewport()->update(); @@ -154,36 +83,18 @@ void TimelineView::SetScale(const double &scale) void TimelineView::SetTimebase(const rational &timebase) { - timebase_ = timebase; - timebase_dbl_ = timebase_.toDouble(); + SetTimebaseInternal(timebase); // Timebase influences position/visibility of playhead viewport()->update(); } -void TimelineView::Clear() -{ - QMapIterator iterator(block_items_); - - while (iterator.hasNext()) { - iterator.next(); - - if (iterator.value() != nullptr) { - delete iterator.value(); - } - } - - block_items_.clear(); -} - void TimelineView::ConnectTimelineNode(TrackList *node) { if (timeline_node_ != nullptr) { disconnect(timeline_node_, SIGNAL(TimebaseChanged(const rational&)), this, SIGNAL(TimebaseChanged(const rational&))); disconnect(timeline_node_, SIGNAL(TimebaseChanged(const rational&)), this, SLOT(SetTimebase(const rational&))); disconnect(timeline_node_, SIGNAL(TimelineCleared()), this, SLOT(Clear())); - disconnect(timeline_node_, SIGNAL(BlockAdded(Block*, int)), this, SLOT(AddBlock(Block*, int))); - disconnect(timeline_node_, SIGNAL(BlockRemoved(Block*)), this, SLOT(RemoveBlock(Block*))); disconnect(timeline_node_, SIGNAL(TrackAdded(TrackOutput*)), this, SLOT(AddTrack(TrackOutput*))); disconnect(timeline_node_, SIGNAL(TrackRemoved(TrackOutput*)), this, SLOT(RemoveTrack(TrackOutput*))); disconnect(timeline_node_, SIGNAL(LengthChanged(const rational&)), this, SLOT(UpdateEndTimeFromTrackList(const rational&))); @@ -195,13 +106,11 @@ void TimelineView::ConnectTimelineNode(TrackList *node) if (timeline_node_ != nullptr) { SetTimebase(timeline_node_->Timebase()); - emit TimebaseChanged(timebase_); + emit TimebaseChanged(timeline_node_->Timebase()); connect(timeline_node_, SIGNAL(TimebaseChanged(const rational&)), this, SIGNAL(TimebaseChanged(const rational&))); connect(timeline_node_, SIGNAL(TimebaseChanged(const rational&)), this, SLOT(SetTimebase(const rational&))); connect(timeline_node_, SIGNAL(TimelineCleared()), this, SLOT(Clear())); - connect(timeline_node_, SIGNAL(BlockAdded(Block*, int)), this, SLOT(AddBlock(Block*, int))); - connect(timeline_node_, SIGNAL(BlockRemoved(Block*)), this, SLOT(RemoveBlock(Block*))); connect(timeline_node_, SIGNAL(TrackAdded(TrackOutput*)), this, SLOT(AddTrack(TrackOutput*))); connect(timeline_node_, SIGNAL(TrackRemoved(TrackOutput*)), this, SLOT(RemoveTrack(TrackOutput*))); connect(timeline_node_, SIGNAL(LengthChanged(const rational&)), this, SLOT(UpdateEndTimeFromTrackList(const rational&))); @@ -251,134 +160,74 @@ void TimelineView::SetTime(const int64_t time) void TimelineView::mousePressEvent(QMouseEvent *event) { - active_tool_ = GetActiveTool(); + TimelineViewMouseEvent timeline_event(ScreenToCoordinate(event->pos()), + event->modifiers()); - // Cache these since we modify the event's later on - Qt::KeyboardModifiers mods = event->modifiers(); + emit MousePressed(&timeline_event); - if (active_tool_ != nullptr) { - setDragMode(active_tool_->drag_mode()); - } - if (active_tool_ == nullptr || active_tool_->enable_default_behavior()) { - // We use Shift for multiple selection while Qt uses Ctrl, we flip those modifiers here to compensate - event->setModifiers(FlipControlAndShiftModifiers(event->modifiers())); - - QGraphicsView::mousePressEvent(event); - } - - if (timeline_node_ != nullptr && active_tool_ != nullptr) { - TimelineViewMouseEvent timeline_event(ScreenToCoordinate(event->pos()), - mods); - - active_tool_->MousePress(&timeline_event); - } } void TimelineView::mouseMoveEvent(QMouseEvent *event) { - // Cache these since we modify the event's later on - Qt::KeyboardModifiers mods = event->modifiers(); + TimelineViewMouseEvent timeline_event(ScreenToCoordinate(event->pos()), + event->modifiers()); - if (active_tool_ == nullptr || active_tool_->enable_default_behavior()) { - // We use Shift for multiple selection while Qt uses Ctrl, we flip those modifiers here to compensate - event->setModifiers(FlipControlAndShiftModifiers(event->modifiers())); - - QGraphicsView::mouseMoveEvent(event); - } - - if (timeline_node_ != nullptr && active_tool_ != nullptr) { - TimelineViewMouseEvent timeline_event(ScreenToCoordinate(event->pos()), - mods); - - active_tool_->MouseMove(&timeline_event); - } + emit MouseMoved(&timeline_event); } void TimelineView::mouseReleaseEvent(QMouseEvent *event) { - // Cache these since we modify the event's later on - Qt::KeyboardModifiers mods = event->modifiers(); + TimelineViewMouseEvent timeline_event(ScreenToCoordinate(event->pos()), + event->modifiers()); - if (active_tool_ == nullptr || active_tool_->enable_default_behavior()) { - // We use Shift for multiple selection while Qt uses Ctrl, we flip those modifiers here to compensate - event->setModifiers(FlipControlAndShiftModifiers(event->modifiers())); - - QGraphicsView::mouseReleaseEvent(event); - } - - if (timeline_node_ != nullptr && active_tool_ != nullptr) { - TimelineViewMouseEvent timeline_event(ScreenToCoordinate(event->pos()), - mods); - - active_tool_->MouseRelease(&timeline_event); - } + emit MouseReleased(&timeline_event); } void TimelineView::mouseDoubleClickEvent(QMouseEvent *event) { - // Cache these since we modify the event's later on - Qt::KeyboardModifiers mods = event->modifiers(); + TimelineViewMouseEvent timeline_event(ScreenToCoordinate(event->pos()), + event->modifiers()); - if (active_tool_ == nullptr || active_tool_->enable_default_behavior()) { - // We use Shift for multiple selection while Qt uses Ctrl, we flip those modifiers here to compensate - event->setModifiers(FlipControlAndShiftModifiers(event->modifiers())); - - QGraphicsView::mouseDoubleClickEvent(event); - } - - if (timeline_node_ != nullptr && active_tool_ != nullptr) { - TimelineViewMouseEvent timeline_event(ScreenToCoordinate(event->pos()), - mods); - - active_tool_->MouseDoubleClick(&timeline_event); - } + emit MouseDoubleClicked(&timeline_event); } void TimelineView::dragEnterEvent(QDragEnterEvent *event) { - if (timeline_node_ != nullptr) { - TimelineViewMouseEvent timeline_event(ScreenToCoordinate(event->pos()), - event->keyboardModifiers()); + TimelineViewMouseEvent timeline_event(ScreenToCoordinate(event->pos()), + event->keyboardModifiers()); - timeline_event.SetMimeData(event->mimeData()); - timeline_event.SetEvent(event); + timeline_event.SetMimeData(event->mimeData()); + timeline_event.SetEvent(event); - import_tool_->DragEnter(&timeline_event); - } + emit DragEntered(&timeline_event); } void TimelineView::dragMoveEvent(QDragMoveEvent *event) { - if (timeline_node_ != nullptr) { - TimelineViewMouseEvent timeline_event(ScreenToCoordinate(event->pos()), - event->keyboardModifiers()); + TimelineViewMouseEvent timeline_event(ScreenToCoordinate(event->pos()), + event->keyboardModifiers()); - timeline_event.SetMimeData(event->mimeData()); - timeline_event.SetEvent(event); + timeline_event.SetMimeData(event->mimeData()); + timeline_event.SetEvent(event); - import_tool_->DragMove(&timeline_event); - } + emit DragMoved(&timeline_event); } void TimelineView::dragLeaveEvent(QDragLeaveEvent *event) { - if (timeline_node_ != nullptr) { - import_tool_->DragLeave(event); - } + emit DragLeft(event); } void TimelineView::dropEvent(QDropEvent *event) { - if (timeline_node_ != nullptr) { - TimelineViewMouseEvent timeline_event(ScreenToCoordinate(event->pos()), - event->keyboardModifiers()); + TimelineViewMouseEvent timeline_event(ScreenToCoordinate(event->pos()), + event->keyboardModifiers()); - timeline_event.SetMimeData(event->mimeData()); - timeline_event.SetEvent(event); + timeline_event.SetMimeData(event->mimeData()); + timeline_event.SetEvent(event); - import_tool_->DragDrop(&timeline_event); - } + emit DragDropped(&timeline_event); } void TimelineView::resizeEvent(QResizeEvent *event) @@ -392,9 +241,9 @@ void TimelineView::drawForeground(QPainter *painter, const QRectF &rect) { QGraphicsView::drawForeground(painter, rect); - if (!timebase_.isNull()) { - double x = TimeToScreenCoord(rational(playhead_ * timebase_.numerator(), timebase_.denominator())); - double width = TimeToScreenCoord(timebase_); + if (!timebase().isNull()) { + double x = TimeToScene(rational(playhead_ * timebase().numerator(), timebase().denominator())); + double width = TimeToScene(timebase()); QRectF playhead_rect(x, rect.top(), width, rect.height()); @@ -444,11 +293,6 @@ TimelineCoordinate TimelineView::SceneToCoordinate(const QPointF& pt) return TimelineCoordinate(SceneToTime(pt.x()), SceneToTrack(pt.y())); } -TimelineView::Tool *TimelineView::GetActiveTool() -{ - return tools_.at(olive::core.tool()).get(); -} - int TimelineView::GetTrackY(int track_index) { int y = 0; @@ -479,20 +323,6 @@ void TimelineView::AddGhost(TimelineViewGhostItem *ghost) scene_.addItem(ghost); } -bool TimelineView::HasGhosts() -{ - return !ghost_items_.isEmpty(); -} - -rational TimelineView::SceneToTime(const double &x) -{ - // Adjust screen point by scale and timebase - qint64 scaled_x_mvmt = qRound64(x / scale_ / timebase_dbl_); - - // Return a time in the timebase - return rational(scaled_x_mvmt * timebase_.numerator(), timebase_.denominator()); -} - int TimelineView::SceneToTrack(double y) { int track = -1; @@ -510,17 +340,6 @@ int TimelineView::SceneToTrack(double y) return track; } -void TimelineView::ClearGhosts() -{ - if (!ghost_items_.isEmpty()) { - foreach (TimelineViewGhostItem* ghost, ghost_items_) { - delete ghost; - } - - ghost_items_.clear(); - } -} - void TimelineView::UserSetTime(const int64_t &time) { SetTime(time); @@ -529,7 +348,7 @@ void TimelineView::UserSetTime(const int64_t &time) rational TimelineView::GetPlayheadTime() { - return rational(playhead_ * timebase_.numerator(), timebase_.denominator()); + return rational(playhead_ * timebase().numerator(), timebase().denominator()); } void TimelineView::BlockChanged() @@ -587,24 +406,3 @@ void TimelineView::SetEndTime(const rational &length) { end_item_->SetEndTime(length); } - -void TimelineView::SetSiblings(TimelineView *a, TimelineView *b) -{ - if (a == b) - return; - - if (!a->siblings_.contains(b)) - a->siblings_.append(b); - - if (!b->siblings_.contains(a)) - b->siblings_.append(a); -} - -void TimelineView::SetSiblings(const QList &siblings) -{ - foreach (TimelineView* view, siblings) { - foreach (TimelineView* sibling, siblings) { - SetSiblings(view, sibling); - } - } -} diff --git a/app/widget/timelineview/timelineview.h b/app/widget/timelineview/timelineview.h index 29b4d4217..6e4850223 100644 --- a/app/widget/timelineview/timelineview.h +++ b/app/widget/timelineview/timelineview.h @@ -62,21 +62,14 @@ public: void SetEndTime(const rational& length); - static void SetSiblings(TimelineView* a, TimelineView* b); - - static void SetSiblings(const QList& siblings); + int GetTrackY(int track_index); + int GetTrackHeight(int track_index); public slots: void SetTimebase(const rational& timebase); void SetTime(const int64_t time); - void Clear(); - - void AddBlock(Block* block, int track); - - void RemoveBlock(Block* block); - void AddTrack(TrackOutput* track); void RemoveTrack(TrackOutput* track); @@ -88,6 +81,16 @@ signals: void TimeChanged(const int64_t& time); + void MousePressed(TimelineViewMouseEvent* event); + void MouseMoved(TimelineViewMouseEvent* event); + void MouseReleased(TimelineViewMouseEvent* event); + void MouseDoubleClicked(TimelineViewMouseEvent* event); + + void DragEntered(TimelineViewMouseEvent* event); + void DragMoved(TimelineViewMouseEvent* event); + void DragLeft(QDragLeaveEvent* event); + void DragDropped(TimelineViewMouseEvent* event); + protected: virtual void mousePressEvent(QMouseEvent *event) override; virtual void mouseMoveEvent(QMouseEvent *event) override; @@ -104,284 +107,28 @@ protected: virtual void drawForeground(QPainter *painter, const QRectF &rect) override; private: - - class Tool - { - public: - Tool(TimelineView* parent); - virtual ~Tool(); - - virtual void MousePress(TimelineViewMouseEvent *){} - virtual void MouseMove(TimelineViewMouseEvent *){} - virtual void MouseRelease(TimelineViewMouseEvent *){} - virtual void MouseDoubleClick(TimelineViewMouseEvent *){} - - virtual void DragEnter(TimelineViewMouseEvent *){} - virtual void DragMove(TimelineViewMouseEvent *){} - virtual void DragLeave(QDragLeaveEvent *){} - virtual void DragDrop(TimelineViewMouseEvent *){} - - TimelineView* parent(); - - static olive::timeline::MovementMode FlipTrimMode(const olive::timeline::MovementMode& trim_mode); - - const DragMode& drag_mode(); - - bool enable_default_behavior(); - - protected: - void set_drag_mode(const DragMode& mode); - - void set_enable_default_behavior(bool enable); - - /** - * @brief Retrieve the QGraphicsItem at a particular scene position - * - * Requires a float-based scene position. If you have a screen position, use GetScenePos() first to convert it to a - * scene position - */ - TimelineViewBlockItem* GetItemAtScenePos(const TimelineCoordinate &coord); - - /** - * @brief Validates Ghosts that are moving horizontally (time-based) - * - * Validation is the process of ensuring that whatever movements the user is making are "valid" and "legal". This - * function's validation ensures that no Ghost's in point ends up in a negative timecode. - */ - rational ValidateFrameMovement(rational movement, const QVector ghosts); - - /** - * @brief Validates Ghosts that are moving vertically (track-based) - * - * This function's validation ensures that no Ghost's track ends up in a negative (non-existent) track. - */ - int ValidateTrackMovement(int movement, const QVector ghosts); - - enum SnapPoints { - kSnapToClips = 0x1, - kSnapToPlayhead = 0x2, - kSnapAll = 0xFF - }; - - /** - * @brief Snaps point `start_point` that is moving by `movement` to currently existing clips - */ - bool SnapPoint(QList start_times, rational *movement, int snap_points = kSnapAll); - - QList snap_points_; - - bool dragging_; - - TimelineCoordinate drag_start_; - - private: - TimelineView* parent_; - - DragMode drag_mode_; - - bool enable_default_behavior_; - - }; - - class PointerTool : public Tool - { - public: - PointerTool(TimelineView* parent); - - virtual void MousePress(TimelineViewMouseEvent *event) override; - virtual void MouseMove(TimelineViewMouseEvent *event) override; - virtual void MouseRelease(TimelineViewMouseEvent *event) override; - protected: - void SetMovementAllowed(bool allowed); - void SetTrackMovementAllowed(bool allowed); - void SetTrimmingAllowed(bool allowed); - virtual void MouseReleaseInternal(TimelineViewMouseEvent *event); - virtual rational FrameValidateInternal(rational time_movement, const QVector &ghosts); - - virtual void InitiateGhosts(TimelineViewBlockItem* clicked_item, - olive::timeline::MovementMode trim_mode, - bool allow_gap_trimming); - - TimelineViewGhostItem* AddGhostFromBlock(Block *block, int track, olive::timeline::MovementMode mode); - - TimelineViewGhostItem* AddGhostFromNull(const rational& in, const rational& out, int track, olive::timeline::MovementMode mode); - - /** - * @brief Validates Ghosts that are getting their in points trimmed - * - * Assumes ghost->data() is a Block. Ensures no Ghost's in point becomes a negative timecode. Also ensures no - * Ghost's length becomes 0 or negative. - */ - rational ValidateInTrimming(rational movement, const QVector ghosts, bool prevent_overwriting); - - /** - * @brief Validates Ghosts that are getting their out points trimmed - * - * Assumes ghost->data() is a Block. Ensures no Ghost's in point becomes a negative timecode. Also ensures no - * Ghost's length becomes 0 or negative. - */ - rational ValidateOutTrimming(rational movement, const QVector ghosts, bool prevent_overwriting); - - virtual void ProcessDrag(const TimelineCoordinate &mouse_pos); - private: - void InitiateDrag(const TimelineCoordinate &mouse_pos); - - void AddGhostInternal(TimelineViewGhostItem* ghost, olive::timeline::MovementMode mode); - - QList GetSelectedClips(); - - bool IsClipTrimmable(TimelineViewBlockItem* clip, - const QList& items, - const olive::timeline::MovementMode& mode); - - int track_start_; - bool movement_allowed_; - bool trimming_allowed_; - bool track_movement_allowed_; - }; - - class ImportTool : public Tool - { - public: - ImportTool(TimelineView* parent); - - virtual void DragEnter(TimelineViewMouseEvent *event) override; - virtual void DragMove(TimelineViewMouseEvent *event) override; - virtual void DragLeave(QDragLeaveEvent *event) override; - virtual void DragDrop(TimelineViewMouseEvent *event) override; - private: - int import_pre_buffer_; - }; - - class RazorTool : public Tool - { - public: - RazorTool(TimelineView* parent); - - virtual void MousePress(TimelineViewMouseEvent *event); - virtual void MouseMove(TimelineViewMouseEvent *event); - virtual void MouseRelease(TimelineViewMouseEvent *event); - - private: - QVector split_tracks_; - }; - - class RippleTool : public PointerTool - { - public: - RippleTool(TimelineView* parent); - protected: - virtual void MouseReleaseInternal(TimelineViewMouseEvent *event) override; - virtual rational FrameValidateInternal(rational time_movement, const QVector& ghosts) override; - - virtual void InitiateGhosts(TimelineViewBlockItem* clicked_item, - olive::timeline::MovementMode trim_mode, - bool allow_gap_trimming) override; - }; - - class RollingTool : public PointerTool - { - public: - RollingTool(TimelineView* parent); - - protected: - virtual void MouseReleaseInternal(TimelineViewMouseEvent *event) override; - virtual rational FrameValidateInternal(rational time_movement, const QVector& ghosts) override; - - virtual void InitiateGhosts(TimelineViewBlockItem* clicked_item, - olive::timeline::MovementMode trim_mode, - bool allow_gap_trimming) override; - }; - - class SlideTool : public PointerTool - { - public: - SlideTool(TimelineView* parent); - - protected: - virtual void MouseReleaseInternal(TimelineViewMouseEvent *event) override; - virtual rational FrameValidateInternal(rational time_movement, const QVector& ghosts) override; - virtual void InitiateGhosts(TimelineViewBlockItem* clicked_item, - olive::timeline::MovementMode trim_mode, - bool allow_gap_trimming) override; - }; - - class SlipTool : public PointerTool - { - public: - SlipTool(TimelineView* parent); - - protected: - virtual void ProcessDrag(const TimelineCoordinate &mouse_pos) override; - virtual void MouseReleaseInternal(TimelineViewMouseEvent *event) override; - }; - - class HandTool : public Tool - { - public: - HandTool(TimelineView* parent); - - private: - QPoint screen_drag_start_; - QPoint scrollbar_start_; - }; - - class ZoomTool : public Tool - { - public: - ZoomTool(TimelineView* parent); - - virtual void MousePress(TimelineViewMouseEvent *event); - virtual void MouseMove(TimelineViewMouseEvent *event); - virtual void MouseRelease(TimelineViewMouseEvent *event); - }; - TrackType ConnectedTrackType(); Stream::Type TrackTypeToStreamType(TrackType track_type); TimelineCoordinate ScreenToCoordinate(const QPoint& pt); TimelineCoordinate SceneToCoordinate(const QPointF& pt); - Tool* GetActiveTool(); - - int GetTrackY(int track_index); - int GetTrackHeight(int track_index); - - QVector< std::shared_ptr > tools_; - - std::shared_ptr import_tool_; - TrackList* timeline_node_; void AddGhost(TimelineViewGhostItem* ghost); - bool HasGhosts(); - - rational SceneToTime(const double &x); int SceneToTrack(double y); - void ClearGhosts(); - void UserSetTime(const int64_t& time); QGraphicsScene scene_; - rational timebase_; - - double timebase_dbl_; - int64_t playhead_; - QMap block_items_; - - QVector ghost_items_; - QVector track_heights_; TimelineViewEndItem* end_item_; - Tool* active_tool_; - TimelinePlayhead playhead_style_; rational GetPlayheadTime(); @@ -392,8 +139,6 @@ private: bool use_tracklist_length_directly_; - QVector siblings_; - private slots: /** * @brief Slot for when a Block node changes its parameters and the graphics need to update diff --git a/app/widget/timelineview/timelineviewblockitem.cpp b/app/widget/timelineview/timelineviewblockitem.cpp index b1690b544..260dff321 100644 --- a/app/widget/timelineview/timelineviewblockitem.cpp +++ b/app/widget/timelineview/timelineviewblockitem.cpp @@ -52,8 +52,8 @@ void TimelineViewBlockItem::UpdateRect() return; } - double item_left = TimeToScreenCoord(block_->in()); - double item_width = TimeToScreenCoord(block_->length()); + double item_left = TimeToScene(block_->in()); + double item_width = TimeToScene(block_->length()); // -1 on width and height so we don't overlap any adjacent clips setRect(0, y_, item_width - 1, height_ - 1); diff --git a/app/widget/timelineview/timelineviewenditem.cpp b/app/widget/timelineview/timelineviewenditem.cpp index 4956e8686..1d66b84ae 100644 --- a/app/widget/timelineview/timelineviewenditem.cpp +++ b/app/widget/timelineview/timelineviewenditem.cpp @@ -25,7 +25,7 @@ void TimelineViewEndItem::UpdateRect() // Doesn't need to be more than one pixel setRect(0, 0, 1, 1); - setPos(TimeToScreenCoord(end_time_) + end_padding_, 0); + setPos(TimeToScene(end_time_) + end_padding_, 0); } void TimelineViewEndItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) diff --git a/app/widget/timelineview/timelineviewghostitem.cpp b/app/widget/timelineview/timelineviewghostitem.cpp index 2b2796db3..c75c83fd6 100644 --- a/app/widget/timelineview/timelineviewghostitem.cpp +++ b/app/widget/timelineview/timelineviewghostitem.cpp @@ -32,7 +32,7 @@ TimelineViewGhostItem::TimelineViewGhostItem(QGraphicsItem *parent) : SetInvisible(false); } -TimelineViewGhostItem *TimelineViewGhostItem::FromBlock(Block *block, int track, int y, int height) +TimelineViewGhostItem *TimelineViewGhostItem::FromBlock(Block *block, const TrackReference& track, int y, int height) { TimelineViewGhostItem* ghost = new TimelineViewGhostItem(); @@ -170,7 +170,7 @@ rational TimelineViewGhostItem::GetAdjustedMediaIn() const return media_in_ + media_in_adj_; } -int TimelineViewGhostItem::GetAdjustedTrack() const +TrackReference TimelineViewGhostItem::GetAdjustedTrack() const { return track_ + track_adj_; } @@ -189,7 +189,7 @@ void TimelineViewGhostItem::UpdateRect() { rational length = GetAdjustedOut() - GetAdjustedIn(); - setRect(0, y_, TimeToScreenCoord(length), height_ - 1); + setRect(0, y_, TimeToScene(length), height_ - 1); - setPos(TimeToScreenCoord(GetAdjustedIn()), 0); + setPos(TimeToScene(GetAdjustedIn()), 0); } diff --git a/app/widget/timelineview/timelineviewghostitem.h b/app/widget/timelineview/timelineviewghostitem.h index 80577590f..95f99e69f 100644 --- a/app/widget/timelineview/timelineviewghostitem.h +++ b/app/widget/timelineview/timelineviewghostitem.h @@ -42,7 +42,7 @@ public: TimelineViewGhostItem(QGraphicsItem* parent = nullptr); - static TimelineViewGhostItem* FromBlock(Block *block, int track, int y, int height); + static TimelineViewGhostItem* FromBlock(Block *block, const TrackReference &track, int y, int height); bool CanHaveZeroLength(); @@ -72,7 +72,7 @@ public: rational GetAdjustedIn() const; rational GetAdjustedOut() const; rational GetAdjustedMediaIn() const; - int GetAdjustedTrack() const; + TrackReference GetAdjustedTrack() const; const olive::timeline::MovementMode& mode() const; void SetMode(const olive::timeline::MovementMode& mode); diff --git a/app/widget/timelineview/timelineviewmouseevent.cpp b/app/widget/timelineview/timelineviewmouseevent.cpp index 592fda769..9f39779f0 100644 --- a/app/widget/timelineview/timelineviewmouseevent.cpp +++ b/app/widget/timelineview/timelineviewmouseevent.cpp @@ -32,7 +32,7 @@ TimelineViewMouseEvent::TimelineViewMouseEvent(const TimelineCoordinate &coord, } TimelineViewMouseEvent::TimelineViewMouseEvent(const rational &frame, - const int &track, + const TrackReference &track, const Qt::KeyboardModifiers &modifiers) : coord_(frame, track), modifiers_(modifiers), diff --git a/app/widget/timelineview/timelineviewmouseevent.h b/app/widget/timelineview/timelineviewmouseevent.h index 61afbb7ba..72d074f24 100644 --- a/app/widget/timelineview/timelineviewmouseevent.h +++ b/app/widget/timelineview/timelineviewmouseevent.h @@ -25,7 +25,7 @@ #include #include -#include "timelinecoordinate.h" +#include "timeline/timelinecoordinate.h" class TimelineViewMouseEvent { @@ -34,7 +34,7 @@ public: const Qt::KeyboardModifiers& modifiers = Qt::NoModifier); TimelineViewMouseEvent(const rational& frame, - const int& track, + const TrackReference &track, const Qt::KeyboardModifiers& modifiers = Qt::NoModifier); const TimelineCoordinate& GetCoordinates(); diff --git a/app/widget/timelineview/timelineviewrect.cpp b/app/widget/timelineview/timelineviewrect.cpp index 69d75f96e..0bae0d2ae 100644 --- a/app/widget/timelineview/timelineviewrect.cpp +++ b/app/widget/timelineview/timelineviewrect.cpp @@ -52,12 +52,12 @@ void TimelineViewRect::SetHeight(const int &height) UpdateRect(); } -const int &TimelineViewRect::Track() +const TrackReference &TimelineViewRect::Track() { return track_; } -void TimelineViewRect::SetTrack(const int &track) +void TimelineViewRect::SetTrack(const TrackReference &track) { track_ = track; } diff --git a/app/widget/timelineview/timelineviewrect.h b/app/widget/timelineview/timelineviewrect.h index 7590ed6aa..a7140708a 100644 --- a/app/widget/timelineview/timelineviewrect.h +++ b/app/widget/timelineview/timelineviewrect.h @@ -23,6 +23,7 @@ #include +#include "timeline/timelinecoordinate.h" #include "timelinescaledobject.h" /** @@ -39,8 +40,8 @@ public: const int& Height(); void SetHeight(const int& height); - const int& Track(); - void SetTrack(const int& track); + const TrackReference& Track(); + void SetTrack(const TrackReference& track); void SetScale(const double& scale); @@ -51,7 +52,7 @@ protected: int height_; - int track_; + TrackReference track_; }; #endif // TIMELINEVIEWRECT_H diff --git a/app/widget/timelineview/tool/hand.cpp b/app/widget/timelineview/tool/hand.cpp index 89d1076a6..dd1a359a9 100644 --- a/app/widget/timelineview/tool/hand.cpp +++ b/app/widget/timelineview/tool/hand.cpp @@ -18,12 +18,12 @@ ***/ -#include "widget/timelineview/timelineview.h" +#include "widget/timelinewidget/timelinewidget.h" #include -TimelineView::HandTool::HandTool(TimelineView* parent) : +TimelineWidget::HandTool::HandTool(TimelineWidget* parent) : Tool(parent) { - set_drag_mode(ScrollHandDrag); + set_drag_mode(QGraphicsView::ScrollHandDrag); } diff --git a/app/widget/timelineview/tool/import.cpp b/app/widget/timelineview/tool/import.cpp index 68e4386c5..f6f83453d 100644 --- a/app/widget/timelineview/tool/import.cpp +++ b/app/widget/timelineview/tool/import.cpp @@ -18,7 +18,7 @@ ***/ -#include "widget/timelineview/timelineview.h" +#include "widget/timelinewidget/timelinewidget.h" #include #include @@ -30,7 +30,26 @@ #include "node/color/opacity/opacity.h" #include "node/input/media/media.h" -TimelineView::ImportTool::ImportTool(TimelineView *parent) : +TrackType TrackTypeFromStreamType(Stream::Type stream_type) +{ + switch (stream_type) { + case Stream::kVideo: + case Stream::kImage: + return kTrackTypeVideo; + case Stream::kAudio: + return kTrackTypeAudio; + case Stream::kSubtitle: + return kTrackTypeSubtitle; + case Stream::kUnknown: + case Stream::kData: + case Stream::kAttachment: + break; + } + + return kTrackTypeNone; +} + +TimelineWidget::ImportTool::ImportTool(TimelineWidget *parent) : Tool(parent) { // Calculate width used for importing to give ghosts a slight lead-in so the ghosts aren't right on the cursor @@ -38,7 +57,7 @@ TimelineView::ImportTool::ImportTool(TimelineView *parent) : import_pre_buffer_ = QFontMetricsWidth(&fm, "HHHHHHHH"); } -void TimelineView::ImportTool::DragEnter(TimelineViewMouseEvent *event) +void TimelineWidget::ImportTool::DragEnter(TimelineViewMouseEvent *event) { QStringList mime_formats = event->GetMimeData()->formats(); @@ -80,30 +99,34 @@ void TimelineView::ImportTool::DragEnter(TimelineViewMouseEvent *event) // Loop through all streams in footage foreach (StreamPtr stream, footage->streams()) { - // Check if this stream is compatible with this TrackList - if (stream->type() == parent()->TrackTypeToStreamType(parent()->ConnectedTrackType())) { - TimelineViewGhostItem* ghost = new TimelineViewGhostItem(); + TrackType track_type = TrackTypeFromStreamType(stream->type()); - if (stream->type() == Stream::kImage) { - // Stream is essentially length-less - use config's default image length - footage_duration = Config::Current()["DefaultStillLength"].value(); - } else { - // Use duration from file - footage_duration = rational(stream->timebase().numerator() * stream->duration(), - stream->timebase().denominator()); - } - - ghost->SetIn(ghost_start); - ghost->SetOut(ghost_start + footage_duration); - - snap_points_.append(ghost->In()); - snap_points_.append(ghost->Out()); - - ghost->setData(TimelineViewGhostItem::kAttachedFootage, QVariant::fromValue(stream)); - ghost->SetMode(olive::timeline::kMove); - - parent()->AddGhost(ghost); + // Check if this stream has a compatible TrackList + if (track_type == kTrackTypeNone) { + continue; } + + TimelineViewGhostItem* ghost = new TimelineViewGhostItem(); + + if (stream->type() == Stream::kImage) { + // Stream is essentially length-less - use config's default image length + footage_duration = Config::Current()["DefaultStillLength"].value(); + } else { + // Use duration from file + footage_duration = rational(stream->timebase().numerator() * stream->duration(), + stream->timebase().denominator()); + } + + ghost->SetIn(ghost_start); + ghost->SetOut(ghost_start + footage_duration); + + snap_points_.append(ghost->In()); + snap_points_.append(ghost->Out()); + + ghost->setData(TimelineViewGhostItem::kAttachedFootage, QVariant::fromValue(stream)); + ghost->SetMode(olive::timeline::kMove); + + parent()->AddGhost(ghost); } // Stack each ghost one after the other @@ -118,12 +141,12 @@ void TimelineView::ImportTool::DragEnter(TimelineViewMouseEvent *event) } } -void TimelineView::ImportTool::DragMove(TimelineViewMouseEvent *event) +void TimelineWidget::ImportTool::DragMove(TimelineViewMouseEvent *event) { if (parent()->HasGhosts()) { rational time_movement = event->GetCoordinates().GetFrame() - drag_start_.GetFrame(); - int ghost_track = event->GetCoordinates().GetTrack(); + const TrackReference& ghost_track = event->GetCoordinates().GetTrack(); int ghost_y = parent()->GetTrackY(ghost_track); int ghost_height = parent()->GetTrackHeight(ghost_track); @@ -150,9 +173,9 @@ void TimelineView::ImportTool::DragMove(TimelineViewMouseEvent *event) } // Generate tooltip (showing earliest in point of imported clip) - int64_t earliest_timestamp = olive::time_to_timestamp(earliest_ghost, parent()->timebase_); + int64_t earliest_timestamp = olive::time_to_timestamp(earliest_ghost, parent()->timebase()); QString tooltip_text = olive::timestamp_to_timecode(earliest_timestamp, - parent()->timebase_, + parent()->timebase(), olive::CurrentTimecodeDisplay()); QToolTip::showText(QCursor::pos(), tooltip_text, @@ -164,7 +187,7 @@ void TimelineView::ImportTool::DragMove(TimelineViewMouseEvent *event) } } -void TimelineView::ImportTool::DragLeave(QDragLeaveEvent* event) +void TimelineWidget::ImportTool::DragLeave(QDragLeaveEvent* event) { if (parent()->HasGhosts()) { parent()->ClearGhosts(); @@ -175,7 +198,7 @@ void TimelineView::ImportTool::DragLeave(QDragLeaveEvent* event) } } -void TimelineView::ImportTool::DragDrop(TimelineViewMouseEvent *event) +void TimelineWidget::ImportTool::DragDrop(TimelineViewMouseEvent *event) { if (parent()->HasGhosts()) { // We use QObject as the parent for the nodes we create. If there is no TimelineOutput node, this object going out @@ -209,7 +232,11 @@ void TimelineView::ImportTool::DragDrop(TimelineViewMouseEvent *event) if (event->GetModifiers() & Qt::ControlModifier) { //emit parent()->RequestInsertBlockAtTime(clip, ghost->GetAdjustedIn()); } else { - new TrackPlaceBlockCommand(parent()->timeline_node_, ghost->Track(), clip, ghost->GetAdjustedIn(), command); + new TrackPlaceBlockCommand(parent()->timeline_node_->track_list(ghost->Track().type()), + ghost->Track().index(), + clip, + ghost->GetAdjustedIn(), + command); } } diff --git a/app/widget/timelineview/tool/pointer.cpp b/app/widget/timelineview/tool/pointer.cpp index 545674dcf..e97d20d5b 100644 --- a/app/widget/timelineview/tool/pointer.cpp +++ b/app/widget/timelineview/tool/pointer.cpp @@ -18,7 +18,7 @@ ***/ -#include "widget/timelineview/timelineview.h" +#include "widget/timelinewidget/timelinewidget.h" #include #include @@ -31,23 +31,23 @@ #include "core.h" #include "node/block/gap/gap.h" -TimelineView::PointerTool::PointerTool(TimelineView *parent) : +TimelineWidget::PointerTool::PointerTool(TimelineWidget *parent) : Tool(parent), movement_allowed_(true), trimming_allowed_(true), track_movement_allowed_(true) { - set_drag_mode(RubberBandDrag); + set_drag_mode(QGraphicsView::RubberBandDrag); set_enable_default_behavior(true); } -void TimelineView::PointerTool::MousePress(TimelineViewMouseEvent *event) +void TimelineWidget::PointerTool::MousePress(TimelineViewMouseEvent *event) { // We don't initiate dragging here since clicking could easily be just for selecting Q_UNUSED(event) } -void TimelineView::PointerTool::MouseMove(TimelineViewMouseEvent *event) +void TimelineWidget::PointerTool::MouseMove(TimelineViewMouseEvent *event) { qDebug() << dragging_ << parent()->ghost_items_.isEmpty(); @@ -68,7 +68,7 @@ void TimelineView::PointerTool::MouseMove(TimelineViewMouseEvent *event) } } -void TimelineView::PointerTool::MouseRelease(TimelineViewMouseEvent *event) +void TimelineWidget::PointerTool::MouseRelease(TimelineViewMouseEvent *event) { if (!parent()->ghost_items_.isEmpty()) { MouseReleaseInternal(event); @@ -82,22 +82,22 @@ void TimelineView::PointerTool::MouseRelease(TimelineViewMouseEvent *event) dragging_ = false; } -void TimelineView::PointerTool::SetMovementAllowed(bool allowed) +void TimelineWidget::PointerTool::SetMovementAllowed(bool allowed) { movement_allowed_ = allowed; } -void TimelineView::PointerTool::SetTrackMovementAllowed(bool allowed) +void TimelineWidget::PointerTool::SetTrackMovementAllowed(bool allowed) { track_movement_allowed_ = allowed; } -void TimelineView::PointerTool::SetTrimmingAllowed(bool allowed) +void TimelineWidget::PointerTool::SetTrimmingAllowed(bool allowed) { trimming_allowed_ = allowed; } -void TimelineView::PointerTool::MouseReleaseInternal(TimelineViewMouseEvent *event) +void TimelineWidget::PointerTool::MouseReleaseInternal(TimelineViewMouseEvent *event) { Q_UNUSED(event) @@ -117,7 +117,10 @@ void TimelineView::PointerTool::MouseReleaseInternal(TimelineViewMouseEvent *eve gap->setParent(&block_memory_manager); gap->set_length(b->length()); - new TrackReplaceBlockCommand(parent()->timeline_node_->TrackAt(ghost->Track()), b, gap, command); + new TrackReplaceBlockCommand(parent()->GetTrackFromReference(ghost->Track()), + b, + gap, + command); } // Now we place the clips back in the timeline where the user moved them. It's legal for them to overwrite parts or @@ -137,13 +140,19 @@ void TimelineView::PointerTool::MouseReleaseInternal(TimelineViewMouseEvent *eve } } - new TrackPlaceBlockCommand(parent()->timeline_node_, ghost->GetAdjustedTrack(), b, ghost->GetAdjustedIn(), command); + const TrackReference& track_ref = ghost->GetAdjustedTrack(); + + new TrackPlaceBlockCommand(parent()->timeline_node_->track_list(track_ref.type()), + track_ref.index(), + b, + ghost->GetAdjustedIn(), + command); } olive::undo_stack.pushIfHasChildren(command); } -rational TimelineView::PointerTool::FrameValidateInternal(rational time_movement, const QVector& ghosts) +rational TimelineWidget::PointerTool::FrameValidateInternal(rational time_movement, const QVector& ghosts) { // Default behavior is to validate all movement and trimming time_movement = ValidateFrameMovement(time_movement, ghosts); @@ -153,7 +162,7 @@ rational TimelineView::PointerTool::FrameValidateInternal(rational time_movement return time_movement; } -void TimelineView::PointerTool::InitiateDrag(const TimelineCoordinate &mouse_pos) +void TimelineWidget::PointerTool::InitiateDrag(const TimelineCoordinate &mouse_pos) { // Record where the drag started in timeline coordinates drag_start_ = mouse_pos; @@ -177,7 +186,7 @@ void TimelineView::PointerTool::InitiateDrag(const TimelineCoordinate &mouse_pos // FIXME: Hardcoded number const int kTrimHandle = 20; - qreal mouse_x = parent()->TimeToScreenCoord(mouse_pos.GetFrame()); + qreal mouse_x = parent()->TimeToScene(mouse_pos.GetFrame()); if (trimming_allowed_ && mouse_x < clicked_item->x() + kTrimHandle) { trim_mode = olive::timeline::kTrimIn; @@ -200,14 +209,14 @@ void TimelineView::PointerTool::InitiateDrag(const TimelineCoordinate &mouse_pos } } -void TimelineView::PointerTool::ProcessDrag(const TimelineCoordinate &mouse_pos) +void TimelineWidget::PointerTool::ProcessDrag(const TimelineCoordinate &mouse_pos) { // Determine track movement - int cursor_track = mouse_pos.GetTrack(); + const TrackReference& cursor_track = mouse_pos.GetTrack(); int track_movement = 0; if (track_movement_allowed_) { - track_movement = cursor_track - track_start_; + track_movement = cursor_track.index() - track_start_.index(); } // Determine frame movement @@ -240,7 +249,7 @@ void TimelineView::PointerTool::ProcessDrag(const TimelineCoordinate &mouse_pos) // Track movement is only legal for moving, not for trimming ghost->SetTrackAdjustment(track_movement); - int track = ghost->GetAdjustedTrack(); + const TrackReference& track = ghost->GetAdjustedTrack(); ghost->SetY(parent()->GetTrackY(track)); ghost->SetHeight(parent()->GetTrackHeight(track)); break; @@ -250,9 +259,9 @@ void TimelineView::PointerTool::ProcessDrag(const TimelineCoordinate &mouse_pos) // Show tooltip // Generate tooltip (showing earliest in point of imported clip) - int64_t earliest_timestamp = olive::time_to_timestamp(time_movement, parent()->timebase_); + int64_t earliest_timestamp = olive::time_to_timestamp(time_movement, parent()->timebase()); QString tooltip_text = olive::timestamp_to_timecode(earliest_timestamp, - parent()->timebase_, + parent()->timebase(), olive::CurrentTimecodeDisplay(), true); QToolTip::showText(QCursor::pos(), @@ -260,7 +269,7 @@ void TimelineView::PointerTool::ProcessDrag(const TimelineCoordinate &mouse_pos) parent()); } -void TimelineView::PointerTool::InitiateGhosts(TimelineViewBlockItem* clicked_item, +void TimelineWidget::PointerTool::InitiateGhosts(TimelineViewBlockItem* clicked_item, olive::timeline::MovementMode trim_mode, bool allow_gap_trimming) { @@ -313,7 +322,7 @@ void TimelineView::PointerTool::InitiateGhosts(TimelineViewBlockItem* clicked_it } } -TimelineViewGhostItem* TimelineView::PointerTool::AddGhostFromBlock(Block* block, int track, olive::timeline::MovementMode mode) +TimelineViewGhostItem* TimelineWidget::PointerTool::AddGhostFromBlock(Block* block, const TrackReference& track, olive::timeline::MovementMode mode) { TimelineViewGhostItem* ghost = TimelineViewGhostItem::FromBlock(block, track, @@ -325,7 +334,7 @@ TimelineViewGhostItem* TimelineView::PointerTool::AddGhostFromBlock(Block* block return ghost; } -TimelineViewGhostItem* TimelineView::PointerTool::AddGhostFromNull(const rational &in, const rational &out, int track, olive::timeline::MovementMode mode) +TimelineViewGhostItem* TimelineWidget::PointerTool::AddGhostFromNull(const rational &in, const rational &out, const TrackReference& track, olive::timeline::MovementMode mode) { TimelineViewGhostItem* ghost = new TimelineViewGhostItem(); @@ -340,7 +349,7 @@ TimelineViewGhostItem* TimelineView::PointerTool::AddGhostFromNull(const rationa return ghost; } -void TimelineView::PointerTool::AddGhostInternal(TimelineViewGhostItem* ghost, olive::timeline::MovementMode mode) +void TimelineWidget::PointerTool::AddGhostInternal(TimelineViewGhostItem* ghost, olive::timeline::MovementMode mode) { ghost->SetScale(parent()->scale_); ghost->SetMode(mode); @@ -365,7 +374,7 @@ void TimelineView::PointerTool::AddGhostInternal(TimelineViewGhostItem* ghost, o parent()->scene_.addItem(ghost); } -QList TimelineView::PointerTool::GetSelectedClips() +QList TimelineWidget::PointerTool::GetSelectedClips() { QList selected_items = parent()->scene_.selectedItems(); @@ -382,7 +391,7 @@ QList TimelineView::PointerTool::GetSelectedClips() return clips; } -bool TimelineView::PointerTool::IsClipTrimmable(TimelineViewBlockItem* clip, +bool TimelineWidget::PointerTool::IsClipTrimmable(TimelineViewBlockItem* clip, const QList& items, const olive::timeline::MovementMode& mode) { @@ -398,7 +407,7 @@ bool TimelineView::PointerTool::IsClipTrimmable(TimelineViewBlockItem* clip, return true; } -rational TimelineView::PointerTool::ValidateInTrimming(rational movement, +rational TimelineWidget::PointerTool::ValidateInTrimming(rational movement, const QVector ghosts, bool prevent_overwriting) { @@ -428,7 +437,7 @@ rational TimelineView::PointerTool::ValidateInTrimming(rational movement, rational latest_in = ghost->Out(); if (!ghost->CanHaveZeroLength()) { - latest_in -= parent()->timebase_; + latest_in -= parent()->timebase(); } // Clamp adjusted value between the earliest and latest values @@ -443,7 +452,7 @@ rational TimelineView::PointerTool::ValidateInTrimming(rational movement, return movement; } -rational TimelineView::PointerTool::ValidateOutTrimming(rational movement, +rational TimelineWidget::PointerTool::ValidateOutTrimming(rational movement, const QVector ghosts, bool prevent_overwriting) { @@ -458,7 +467,7 @@ rational TimelineView::PointerTool::ValidateOutTrimming(rational movement, rational earliest_out = ghost->In(); if (!ghost->CanHaveZeroLength()) { - earliest_out += parent()->timebase_; + earliest_out += parent()->timebase(); } rational latest_out = RATIONAL_MAX; diff --git a/app/widget/timelineview/tool/razor.cpp b/app/widget/timelineview/tool/razor.cpp index b6e02f206..f0bbee60e 100644 --- a/app/widget/timelineview/tool/razor.cpp +++ b/app/widget/timelineview/tool/razor.cpp @@ -18,21 +18,21 @@ ***/ -#include "widget/timelineview/timelineview.h" +#include "widget/timelinewidget/timelinewidget.h" -TimelineView::RazorTool::RazorTool(TimelineView* parent) : +TimelineWidget::RazorTool::RazorTool(TimelineWidget* parent) : Tool(parent) { } -void TimelineView::RazorTool::MousePress(TimelineViewMouseEvent *event) +void TimelineWidget::RazorTool::MousePress(TimelineViewMouseEvent *event) { split_tracks_.clear(); MouseMove(event); } -void TimelineView::RazorTool::MouseMove(TimelineViewMouseEvent *event) +void TimelineWidget::RazorTool::MouseMove(TimelineViewMouseEvent *event) { if (!dragging_) { drag_start_ = event->GetCoordinates(); @@ -40,14 +40,14 @@ void TimelineView::RazorTool::MouseMove(TimelineViewMouseEvent *event) } // Split at the current cursor track - int split_track = event->GetCoordinates().GetTrack(); + TrackReference split_track = event->GetCoordinates().GetTrack(); if (!split_tracks_.contains(split_track)) { split_tracks_.append(split_track); } } -void TimelineView::RazorTool::MouseRelease(TimelineViewMouseEvent *event) +void TimelineWidget::RazorTool::MouseRelease(TimelineViewMouseEvent *event) { Q_UNUSED(event) @@ -56,8 +56,8 @@ void TimelineView::RazorTool::MouseRelease(TimelineViewMouseEvent *event) QUndoCommand* command = new QUndoCommand(); - foreach (int track, split_tracks_) { - new TrackSplitAtTimeCommand(parent()->timeline_node_->TrackAt(track), split_time, command); + foreach (const TrackReference& track, split_tracks_) { + new TrackSplitAtTimeCommand(parent()->GetTrackFromReference(track), split_time, command); } split_tracks_.clear(); diff --git a/app/widget/timelineview/tool/ripple.cpp b/app/widget/timelineview/tool/ripple.cpp index a42345ad0..c1214c2d7 100644 --- a/app/widget/timelineview/tool/ripple.cpp +++ b/app/widget/timelineview/tool/ripple.cpp @@ -18,17 +18,17 @@ ***/ -#include "widget/timelineview/timelineview.h" +#include "widget/timelinewidget/timelinewidget.h" #include "node/block/gap/gap.h" -TimelineView::RippleTool::RippleTool(TimelineView* parent) : +TimelineWidget::RippleTool::RippleTool(TimelineWidget* parent) : PointerTool(parent) { SetMovementAllowed(false); } -void TimelineView::RippleTool::MouseReleaseInternal(TimelineViewMouseEvent *event) +void TimelineWidget::RippleTool::MouseReleaseInternal(TimelineViewMouseEvent *event) { Q_UNUSED(event) @@ -51,7 +51,7 @@ void TimelineView::RippleTool::MouseReleaseInternal(TimelineViewMouseEvent *even Block* block_to_append_gap_to = Node::ValueToPtr(ghost->data(TimelineViewGhostItem::kReferenceBlock)); - new TrackInsertBlockBetweenBlocksCommand(parent()->timeline_node_->Tracks().at(ghost->Track()), + new TrackInsertBlockBetweenBlocksCommand(parent()->GetTrackFromReference(ghost->Track()), gap, block_to_append_gap_to, block_to_append_gap_to->next()); @@ -67,7 +67,7 @@ void TimelineView::RippleTool::MouseReleaseInternal(TimelineViewMouseEvent *even } } else { // Assumed the Block was a Gap and it was reduced to zero length, remove it here - new TrackRippleRemoveBlockCommand(parent()->timeline_node_->Tracks().at(ghost->Track()), b, command); + new TrackRippleRemoveBlockCommand(parent()->GetTrackFromReference(ghost->Track()), b, command); } } } @@ -75,7 +75,7 @@ void TimelineView::RippleTool::MouseReleaseInternal(TimelineViewMouseEvent *even olive::undo_stack.pushIfHasChildren(command); } -rational TimelineView::RippleTool::FrameValidateInternal(rational time_movement, const QVector &ghosts) +rational TimelineWidget::RippleTool::FrameValidateInternal(rational time_movement, const QVector &ghosts) { // Only validate trimming, and we don't care about "overwriting" since the ripple tool is nondestructive time_movement = ValidateInTrimming(time_movement, ghosts, false); @@ -84,7 +84,7 @@ rational TimelineView::RippleTool::FrameValidateInternal(rational time_movement, return time_movement; } -void TimelineView::RippleTool::InitiateGhosts(TimelineViewBlockItem *clicked_item, +void TimelineWidget::RippleTool::InitiateGhosts(TimelineViewBlockItem *clicked_item, olive::timeline::MovementMode trim_mode, bool allow_gap_trimming) { @@ -117,7 +117,7 @@ void TimelineView::RippleTool::InitiateGhosts(TimelineViewBlockItem *clicked_ite bool ghost_on_this_track_exists = false; foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) { - if (ghost->Track() == track->Index()) { + if (parent()->GetTrackFromReference(ghost->Track()) == track) { ghost_on_this_track_exists = true; break; } diff --git a/app/widget/timelineview/tool/rolling.cpp b/app/widget/timelineview/tool/rolling.cpp index 2db6f8bc6..2dabbafca 100644 --- a/app/widget/timelineview/tool/rolling.cpp +++ b/app/widget/timelineview/tool/rolling.cpp @@ -18,17 +18,17 @@ ***/ -#include "widget/timelineview/timelineview.h" +#include "widget/timelinewidget/timelinewidget.h" #include "node/block/gap/gap.h" -TimelineView::RollingTool::RollingTool(TimelineView* parent) : +TimelineWidget::RollingTool::RollingTool(TimelineWidget* parent) : PointerTool(parent) { SetMovementAllowed(false); } -void TimelineView::RollingTool::MouseReleaseInternal(TimelineViewMouseEvent *event) +void TimelineWidget::RollingTool::MouseReleaseInternal(TimelineViewMouseEvent *event) { Q_UNUSED(event) @@ -44,13 +44,19 @@ void TimelineView::RollingTool::MouseReleaseInternal(TimelineViewMouseEvent *eve GapBlock* gap = new GapBlock(); gap->set_length(ghost->Length()); - new TrackReplaceBlockCommand(parent()->timeline_node_->TrackAt(ghost->Track()), b, gap, command); + new TrackReplaceBlockCommand(parent()->GetTrackFromReference(ghost->Track()), b, gap, command); } new BlockResizeWithMediaInCommand(b, ghost->AdjustedLength(), command); if (b->previous() == nullptr) { - new TrackPlaceBlockCommand(parent()->timeline_node_, ghost->Track(), b, ghost->GetAdjustedIn(), command); + const TrackReference& track_ref = ghost->Track(); + + new TrackPlaceBlockCommand(parent()->timeline_node_->track_list(track_ref.type()), + track_ref.index(), + b, + ghost->GetAdjustedIn(), + command); } } else if (ghost->mode() == olive::timeline::kTrimOut) { new BlockResizeCommand(b, ghost->AdjustedLength(), command); @@ -60,7 +66,7 @@ void TimelineView::RollingTool::MouseReleaseInternal(TimelineViewMouseEvent *eve olive::undo_stack.pushIfHasChildren(command); } -rational TimelineView::RollingTool::FrameValidateInternal(rational time_movement, const QVector &ghosts) +rational TimelineWidget::RollingTool::FrameValidateInternal(rational time_movement, const QVector &ghosts) { // Only validate trimming, and we don't care about "overwriting" since the rolling tool is designed to trim at collisions time_movement = ValidateInTrimming(time_movement, ghosts, false); @@ -69,7 +75,7 @@ rational TimelineView::RollingTool::FrameValidateInternal(rational time_movement return time_movement; } -void TimelineView::RollingTool::InitiateGhosts(TimelineViewBlockItem *clicked_item, +void TimelineWidget::RollingTool::InitiateGhosts(TimelineViewBlockItem *clicked_item, olive::timeline::MovementMode trim_mode, bool allow_gap_trimming) { diff --git a/app/widget/timelineview/tool/slide.cpp b/app/widget/timelineview/tool/slide.cpp index 46d89e313..00cd8f546 100644 --- a/app/widget/timelineview/tool/slide.cpp +++ b/app/widget/timelineview/tool/slide.cpp @@ -18,18 +18,18 @@ ***/ -#include "widget/timelineview/timelineview.h" +#include "widget/timelinewidget/timelinewidget.h" #include "node/block/gap/gap.h" -TimelineView::SlideTool::SlideTool(TimelineView* parent) : +TimelineWidget::SlideTool::SlideTool(TimelineWidget* parent) : PointerTool(parent) { SetTrimmingAllowed(false); SetTrackMovementAllowed(false); } -void TimelineView::SlideTool::MouseReleaseInternal(TimelineViewMouseEvent *event) +void TimelineWidget::SlideTool::MouseReleaseInternal(TimelineViewMouseEvent *event) { Q_UNUSED(event) @@ -46,14 +46,14 @@ void TimelineView::SlideTool::MouseReleaseInternal(TimelineViewMouseEvent *event } else if (ghost->mode() == olive::timeline::kMove && b->previous() == nullptr) { GapBlock* gap = new GapBlock(); gap->set_length(ghost->InAdjustment()); - new TrackPrependBlockCommand(parent()->timeline_node_->TrackAt(ghost->Track()), gap, command); + new TrackPrependBlockCommand(parent()->GetTrackFromReference(ghost->Track()), gap, command); } } olive::undo_stack.pushIfHasChildren(command); } -rational TimelineView::SlideTool::FrameValidateInternal(rational time_movement, const QVector &ghosts) +rational TimelineWidget::SlideTool::FrameValidateInternal(rational time_movement, const QVector &ghosts) { // Only validate trimming, and we don't care about "overwriting" since the rolling tool is designed to trim at collisions time_movement = ValidateInTrimming(time_movement, ghosts, false); @@ -62,7 +62,7 @@ rational TimelineView::SlideTool::FrameValidateInternal(rational time_movement, return time_movement; } -void TimelineView::SlideTool::InitiateGhosts(TimelineViewBlockItem *clicked_item, +void TimelineWidget::SlideTool::InitiateGhosts(TimelineViewBlockItem *clicked_item, olive::timeline::MovementMode trim_mode, bool allow_gap_trimming) { diff --git a/app/widget/timelineview/tool/slip.cpp b/app/widget/timelineview/tool/slip.cpp index a095ac99b..97c6348ac 100644 --- a/app/widget/timelineview/tool/slip.cpp +++ b/app/widget/timelineview/tool/slip.cpp @@ -18,21 +18,21 @@ ***/ -#include "widget/timelineview/timelineview.h" +#include "widget/timelinewidget/timelinewidget.h" #include #include "common/timecodefunctions.h" #include "config/config.h" -TimelineView::SlipTool::SlipTool(TimelineView *parent) : +TimelineWidget::SlipTool::SlipTool(TimelineWidget *parent) : PointerTool(parent) { SetTrimmingAllowed(false); SetTrackMovementAllowed(false); } -void TimelineView::SlipTool::ProcessDrag(const TimelineCoordinate &mouse_pos) +void TimelineWidget::SlipTool::ProcessDrag(const TimelineCoordinate &mouse_pos) { // Determine frame movement rational time_movement = drag_start_.GetFrame() - mouse_pos.GetFrame(); @@ -51,9 +51,9 @@ void TimelineView::SlipTool::ProcessDrag(const TimelineCoordinate &mouse_pos) // Show tooltip // Generate tooltip (showing earliest in point of imported clip) - int64_t earliest_timestamp = olive::time_to_timestamp(time_movement, parent()->timebase_); + int64_t earliest_timestamp = olive::time_to_timestamp(time_movement, parent()->timebase()); QString tooltip_text = olive::timestamp_to_timecode(earliest_timestamp, - parent()->timebase_, + parent()->timebase(), olive::CurrentTimecodeDisplay(), true); QToolTip::showText(QCursor::pos(), @@ -61,7 +61,7 @@ void TimelineView::SlipTool::ProcessDrag(const TimelineCoordinate &mouse_pos) parent()); } -void TimelineView::SlipTool::MouseReleaseInternal(TimelineViewMouseEvent *event) +void TimelineWidget::SlipTool::MouseReleaseInternal(TimelineViewMouseEvent *event) { Q_UNUSED(event) diff --git a/app/widget/timelineview/tool/tool.cpp b/app/widget/timelineview/tool/tool.cpp index 6b5219e12..c7602a45a 100644 --- a/app/widget/timelineview/tool/tool.cpp +++ b/app/widget/timelineview/tool/tool.cpp @@ -18,30 +18,30 @@ ***/ -#include "widget/timelineview/timelineview.h" +#include "widget/timelinewidget/timelinewidget.h" #include #include "common/range.h" -TimelineView::Tool::Tool(TimelineView *parent) : +TimelineWidget::Tool::Tool(TimelineWidget *parent) : dragging_(false), parent_(parent), - drag_mode_(NoDrag), + drag_mode_(QGraphicsView::NoDrag), enable_default_behavior_(false) { } -TimelineView::Tool::~Tool() +TimelineWidget::Tool::~Tool() { } -TimelineView *TimelineView::Tool::parent() +TimelineWidget *TimelineWidget::Tool::parent() { return parent_; } -olive::timeline::MovementMode TimelineView::Tool::FlipTrimMode(const olive::timeline::MovementMode &trim_mode) +olive::timeline::MovementMode TimelineWidget::Tool::FlipTrimMode(const olive::timeline::MovementMode &trim_mode) { if (trim_mode == olive::timeline::kTrimIn) { return olive::timeline::kTrimOut; @@ -54,27 +54,27 @@ olive::timeline::MovementMode TimelineView::Tool::FlipTrimMode(const olive::time return trim_mode; } -const QGraphicsView::DragMode &TimelineView::Tool::drag_mode() +const QGraphicsView::DragMode &TimelineWidget::Tool::drag_mode() { return drag_mode_; } -bool TimelineView::Tool::enable_default_behavior() +bool TimelineWidget::Tool::enable_default_behavior() { return enable_default_behavior_; } -void TimelineView::Tool::set_drag_mode(const QGraphicsView::DragMode &mode) +void TimelineWidget::Tool::set_drag_mode(const QGraphicsView::DragMode &mode) { drag_mode_ = mode; } -void TimelineView::Tool::set_enable_default_behavior(bool enable) +void TimelineWidget::Tool::set_enable_default_behavior(bool enable) { enable_default_behavior_ = enable; } -TimelineViewBlockItem *TimelineView::Tool::GetItemAtScenePos(const TimelineCoordinate& coord) +TimelineViewBlockItem *TimelineWidget::Tool::GetItemAtScenePos(const TimelineCoordinate& coord) { QMapIterator iterator(parent()->block_items_); @@ -116,7 +116,7 @@ void AttemptSnap(const QList& proposed_pts, } } -rational TimelineView::Tool::ValidateFrameMovement(rational movement, const QVector ghosts) +rational TimelineWidget::Tool::ValidateFrameMovement(rational movement, const QVector ghosts) { foreach (TimelineViewGhostItem* ghost, ghosts) { if (ghost->mode() != olive::timeline::kMove) { @@ -132,26 +132,24 @@ rational TimelineView::Tool::ValidateFrameMovement(rational movement, const QVec return movement; } -int TimelineView::Tool::ValidateTrackMovement(int movement, const QVector ghosts) +int TimelineWidget::Tool::ValidateTrackMovement(int movement, const QVector ghosts) { foreach (TimelineViewGhostItem* ghost, ghosts) { // Prevents any ghosts from going to a non-existent negative track - if (ghost->Track() + movement < 0) { + if (ghost->Track().index() + movement < 0) { if (ghost->mode() != olive::timeline::kMove) { continue; } - movement = -ghost->Track(); + movement = -ghost->Track().index(); } } return movement; } -bool TimelineView::Tool::SnapPoint(QList start_times, rational* movement, int snap_points) +bool TimelineWidget::Tool::SnapPoint(QList start_times, rational* movement, int snap_points) { - QList items = parent()->scene_.items(); - double diff = DBL_MAX; QList proposed_pts; @@ -163,8 +161,8 @@ bool TimelineView::Tool::SnapPoint(QList start_times, rational* moveme if (snap_points & kSnapToPlayhead) { - rational playhead_abs_time = rational(parent()->playhead_ * parent()->timebase_.numerator(), - parent()->timebase_.denominator()); + rational playhead_abs_time = rational(parent()->playhead_ * parent()->timebase().numerator(), + parent()->timebase().denominator()); qreal playhead_pos = playhead_abs_time.toDouble() * parent()->scale_; @@ -172,18 +170,22 @@ bool TimelineView::Tool::SnapPoint(QList start_times, rational* moveme } if (snap_points & kSnapToClips) { - foreach (QGraphicsItem* it, items) { - TimelineViewBlockItem* timeline_rect = dynamic_cast(it); + QMapIterator iterator(parent()->block_items_); - if (timeline_rect != nullptr) { - qreal rect_left = timeline_rect->x(); - qreal rect_right = rect_left + timeline_rect->rect().width(); + while (iterator.hasNext()) { + iterator.next(); + + TimelineViewBlockItem* item = iterator.value(); + + if (item != nullptr) { + qreal rect_left = item->x(); + qreal rect_right = rect_left + item->rect().width(); // Attempt snapping to clip in point - AttemptSnap(proposed_pts, rect_left, start_times, timeline_rect->block()->in(), movement, &diff); + AttemptSnap(proposed_pts, rect_left, start_times, item->block()->in(), movement, &diff); // Attempt snapping to clip out point - AttemptSnap(proposed_pts, rect_right, start_times, timeline_rect->block()->out(), movement, &diff); + AttemptSnap(proposed_pts, rect_right, start_times, item->block()->out(), movement, &diff); } } } diff --git a/app/widget/timelineview/tool/zoom.cpp b/app/widget/timelineview/tool/zoom.cpp index 6215fba8b..d208ea7ec 100644 --- a/app/widget/timelineview/tool/zoom.cpp +++ b/app/widget/timelineview/tool/zoom.cpp @@ -18,36 +18,29 @@ ***/ -#include "widget/timelineview/timelineview.h" +#include "widget/timelinewidget/timelinewidget.h" -TimelineView::ZoomTool::ZoomTool(TimelineView* parent) : +TimelineWidget::ZoomTool::ZoomTool(TimelineWidget *parent) : Tool(parent) { } -void TimelineView::ZoomTool::MousePress(TimelineViewMouseEvent *event) +void TimelineWidget::ZoomTool::MousePress(TimelineViewMouseEvent *event) { Q_UNUSED(event) } -void TimelineView::ZoomTool::MouseMove(TimelineViewMouseEvent *event) +void TimelineWidget::ZoomTool::MouseMove(TimelineViewMouseEvent *event) { Q_UNUSED(event) } -void TimelineView::ZoomTool::MouseRelease(TimelineViewMouseEvent *event) +void TimelineWidget::ZoomTool::MouseRelease(TimelineViewMouseEvent *event) { double scale = parent()->scale_; - // Get center of viewport - QPoint viewport_center = parent()->viewport()->rect().center(); - QPointF scene_center = parent()->mapToScene(viewport_center); - - // Set X to time - scene_center.setX(parent()->TimeToScreenCoord(event->GetCoordinates().GetFrame())); - // Normalize zoom location for 1.0 scale - double scaled_x = scene_center.x() / scale; + double frame_x = parent()->TimeToScene(event->GetCoordinates().GetFrame()); if (event->GetModifiers() & Qt::AltModifier) { // Zoom out if the user clicks while holding Alt @@ -58,11 +51,9 @@ void TimelineView::ZoomTool::MouseRelease(TimelineViewMouseEvent *event) } parent()->SetScale(scale); - emit parent()->ScaleChanged(scale); // Adjust zoom location for new scale - scaled_x *= scale; - scene_center.setX(scaled_x); + frame_x *= scale; - parent()->centerOn(scene_center); + parent()->CenterOn(frame_x); } diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index 8ee886c32..14291f250 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -4,7 +4,9 @@ #include #include +#include "core.h" #include "common/timecodefunctions.h" +#include "tool/tool.h" TimelineWidget::TimelineWidget(QWidget *parent) : QWidget(parent), @@ -32,8 +34,24 @@ TimelineWidget::TimelineWidget(QWidget *parent) : // Audio view views_.append(new TimelineView(Qt::AlignTop)); - // Set both views as siblings - TimelineView::SetSiblings(views_); + // Create tools + tools_.resize(olive::tool::kCount); + tools_.fill(nullptr); + + tools_.replace(olive::tool::kPointer, std::make_shared(this)); + // tools_.replace(olive::tool::kEdit, new PointerTool(this)); FIXME: Implement + tools_.replace(olive::tool::kRipple, std::make_shared(this)); + tools_.replace(olive::tool::kRolling, std::make_shared(this)); + tools_.replace(olive::tool::kRazor, std::make_shared(this)); + tools_.replace(olive::tool::kSlip, std::make_shared(this)); + tools_.replace(olive::tool::kSlide, std::make_shared(this)); + tools_.replace(olive::tool::kHand, std::make_shared(this)); + tools_.replace(olive::tool::kZoom, std::make_shared(this)); + //tools_.replace(olive::tool::kTransition, new (this)); FIXME: Implement + //tools_.replace(olive::tool::kRecord, new PointerTool(this)); FIXME: Implement + //tools_.replace(olive::tool::kAdd, new PointerTool(this)); FIXME: Implement + + import_tool_ = std::make_shared(this); // Global scrollbar horizontal_scroll_ = new QScrollBar(Qt::Horizontal); @@ -75,14 +93,22 @@ void TimelineWidget::Clear() { SetTimebase(0); - foreach (TimelineView* view, views_) { - view->Clear(); + QMapIterator iterator(block_items_); + + while (iterator.hasNext()) { + iterator.next(); + + if (iterator.value() != nullptr) { + delete iterator.value(); + } } + + block_items_.clear(); } void TimelineWidget::SetTimebase(const rational &timebase) { - timebase_ = timebase; + SetTimebaseInternal(timebase); ruler_->SetTimebase(timebase); @@ -113,20 +139,20 @@ void TimelineWidget::ConnectTimelineNode(TimelineOutput *node) { if (timeline_node_ != nullptr) { disconnect(timeline_node_, SIGNAL(LengthChanged(const rational&)), this, SLOT(UpdateTimelineLength(const rational&))); + disconnect(timeline_node_, SIGNAL(BlockAdded(Block*, TrackReference)), this, SLOT(AddBlock(Block*, TrackReference))); + disconnect(timeline_node_, SIGNAL(BlockRemoved(Block*)), this, SLOT(RemoveBlock(Block*))); } timeline_node_ = node; - int track_type = 0; - - foreach (TimelineView* view, views_) { - view->ConnectTimelineNode(node->track_list(static_cast(track_type))); - - track_type++; + for (int track_type=0;track_typeConnectTimelineNode(node->track_list(static_cast(track_type))); } if (timeline_node_ != nullptr) { connect(timeline_node_, SIGNAL(LengthChanged(const rational&)), this, SLOT(UpdateTimelineLength(const rational&))); + connect(timeline_node_, SIGNAL(BlockAdded(Block*, TrackReference)), this, SLOT(AddBlock(Block*, TrackReference))); + connect(timeline_node_, SIGNAL(BlockRemoved(Block*)), this, SLOT(RemoveBlock(Block*))); foreach (TimelineView* view, views_) { view->SetEndTime(timeline_node_->timeline_length()); @@ -203,7 +229,7 @@ void TimelineWidget::GoToPrevCut() int64_t this_track_closest_cut = 0; foreach (Block* block, track->Blocks()) { - int64_t block_out_ts = olive::time_to_timestamp(block->out(), timebase_); + int64_t block_out_ts = olive::time_to_timestamp(block->out(), timebase()); if (block_out_ts < playhead_) { this_track_closest_cut = block_out_ts; @@ -227,14 +253,14 @@ void TimelineWidget::GoToNextCut() int64_t closest_cut = INT64_MAX; foreach (TrackOutput* track, timeline_node_->Tracks()) { - int64_t this_track_closest_cut = olive::time_to_timestamp(track->in(), timebase_); + int64_t this_track_closest_cut = olive::time_to_timestamp(track->in(), timebase()); if (this_track_closest_cut <= playhead_) { this_track_closest_cut = INT64_MAX; } foreach (Block* block, track->Blocks()) { - int64_t block_in_ts = olive::time_to_timestamp(block->in(), timebase_); + int64_t block_in_ts = olive::time_to_timestamp(block->in(), timebase()); if (block_in_ts > playhead_) { this_track_closest_cut = block_in_ts; @@ -252,7 +278,7 @@ void TimelineWidget::GoToNextCut() void TimelineWidget::RippleEditTo(olive::timeline::MovementMode mode, bool insert_gaps) { - rational playhead_time = olive::timestamp_to_time(playhead_, timebase_); + rational playhead_time = olive::timestamp_to_time(playhead_, timebase()); rational closest_point_to_playhead; if (mode == olive::timeline::kTrimIn) { @@ -278,9 +304,9 @@ void TimelineWidget::RippleEditTo(olive::timeline::MovementMode mode, bool inser if (closest_point_to_playhead == playhead_time) { // Remove one frame only if (mode == olive::timeline::kTrimIn) { - playhead_time += timebase_; + playhead_time += timebase(); } else { - playhead_time -= timebase_; + playhead_time -= timebase(); } } @@ -304,7 +330,7 @@ void TimelineWidget::RippleEditTo(olive::timeline::MovementMode mode, bool inser olive::undo_stack.pushIfHasChildren(command); if (mode == olive::timeline::kTrimIn && !insert_gaps) { - int64_t new_time = olive::time_to_timestamp(closest_point_to_playhead, timebase_); + int64_t new_time = olive::time_to_timestamp(closest_point_to_playhead, timebase()); SetTimeAndSignal(new_time); } @@ -316,17 +342,67 @@ void TimelineWidget::SetTimeAndSignal(const int64_t &t) emit TimeChanged(t); } +TrackOutput *TimelineWidget::GetTrackFromReference(const TrackReference &ref) +{ + return timeline_node_->track_list(ref.type())->TrackAt(ref.index()); +} + +int TimelineWidget::GetTrackY(const TrackReference &ref) +{ + return views_.at(ref.type())->GetTrackY(ref.index()); +} + +int TimelineWidget::GetTrackHeight(const TrackReference &ref) +{ + return views_.at(ref.type())->GetTrackHeight(ref.index()); +} + +void TimelineWidget::CenterOn(qreal scene_pos) +{ + horizontal_scroll_->setValue(qRound(scene_pos - horizontal_scroll_->width()/2)); +} + void TimelineWidget::SetScale(double scale) { scale_ = scale; ruler_->SetScale(scale_); + QMapIterator iterator(block_items_); + + while (iterator.hasNext()) { + iterator.next(); + + if (iterator.value() != nullptr) { + iterator.value()->SetScale(scale_); + } + } + + foreach (TimelineViewGhostItem* ghost, ghost_items_) { + ghost->SetScale(scale_); + } + foreach (TimelineView* view, views_) { view->SetScale(scale_); } } +void TimelineWidget::ClearGhosts() +{ + if (!ghost_items_.isEmpty()) { + foreach (TimelineViewGhostItem* ghost, ghost_items_) { + delete ghost; + } + + ghost_items_.clear(); + } +} + +bool TimelineWidget::HasGhosts() +{ + return !ghost_items_.isEmpty(); +} + void TimelineWidget::UpdateInternalTime(const int64_t ×tamp) { playhead_ = timestamp; @@ -338,3 +414,103 @@ void TimelineWidget::UpdateTimelineLength(const rational &length) view->SetEndTime(length); } } + +TimelineWidget::Tool *TimelineWidget::GetActiveTool() +{ + return tools_.at(olive::core.tool()).get(); +} + +void TimelineWidget::ViewMousePressed(TimelineViewMouseEvent *event) +{ + active_tool_ = GetActiveTool(); + + if (timeline_node_ != nullptr && active_tool_ != nullptr) { + active_tool_->MousePress(event); + } +} + +void TimelineWidget::ViewMouseMoved(TimelineViewMouseEvent *event) +{ + if (timeline_node_ != nullptr && active_tool_ != nullptr) { + active_tool_->MouseMove(event); + } +} + +void TimelineWidget::ViewMouseReleased(TimelineViewMouseEvent *event) +{ + if (timeline_node_ != nullptr && active_tool_ != nullptr) { + active_tool_->MouseRelease(event); + } +} + +void TimelineWidget::ViewMouseDoubleClicked(TimelineViewMouseEvent *event) +{ + if (timeline_node_ != nullptr && active_tool_ != nullptr) { + active_tool_->MouseDoubleClick(event); + } +} + +void TimelineWidget::ViewDragEntered(TimelineViewMouseEvent *event) +{ + if (timeline_node_ != nullptr) { + import_tool_->DragEnter(event); + } +} + +void TimelineWidget::ViewDragMoved(TimelineViewMouseEvent *event) +{ + if (timeline_node_ != nullptr) { + import_tool_->DragMove(event); + } +} + +void TimelineWidget::ViewDragLeft(QDragLeaveEvent *event) +{ + if (timeline_node_ != nullptr) { + import_tool_->DragLeave(event); + } +} + +void TimelineWidget::ViewDragDropped(TimelineViewMouseEvent *event) +{ + if (timeline_node_ != nullptr) { + import_tool_->DragDrop(event); + } +} + +void TimelineWidget::AddBlock(Block *block, TrackReference track) +{ + switch (block->type()) { + case Block::kClip: + case Block::kGap: + { + TimelineViewBlockItem* item = new TimelineViewBlockItem(); + + // Set up clip with view parameters (clip item will automatically size its rect accordingly) + item->SetBlock(block); + item->SetY(GetTrackY(track)); + item->SetHeight(GetTrackHeight(track)); + item->SetScale(scale_); + item->SetTrack(track); + + // Add to list of clip items that can be iterated through + block_items_.insert(block, item); + + // Add item to graphics scene + views_.at(track.type())->scene()->addItem(item); + + connect(block, SIGNAL(Refreshed()), this, SLOT(BlockChanged())); + break; + } + case Block::kEnd: + // Do nothing + break; + } +} + +void TimelineWidget::RemoveBlock(Block *block) +{ + delete block_items_[block]; + + block_items_.remove(block); +} diff --git a/app/widget/timelinewidget/timelinewidget.h b/app/widget/timelinewidget/timelinewidget.h index b68b15c8f..c75a7045e 100644 --- a/app/widget/timelinewidget/timelinewidget.h +++ b/app/widget/timelinewidget/timelinewidget.h @@ -4,6 +4,7 @@ #include #include +#include "widget/timelineview/timelinescaledobject.h" #include "widget/timelineview/timelineview.h" #include "widget/timeruler/timeruler.h" @@ -12,7 +13,7 @@ * * Encapsulates TimelineViews, TimeRulers, and scrollbars for a complete widget to manipulate Timelines */ -class TimelineWidget : public QWidget +class TimelineWidget : public QWidget, public TimelineScaledObject { Q_OBJECT public: @@ -56,24 +57,274 @@ signals: void TimeChanged(const int64_t& time); private: + class Tool + { + public: + Tool(TimelineWidget* parent); + virtual ~Tool(); + + virtual void MousePress(TimelineViewMouseEvent *){} + virtual void MouseMove(TimelineViewMouseEvent *){} + virtual void MouseRelease(TimelineViewMouseEvent *){} + virtual void MouseDoubleClick(TimelineViewMouseEvent *){} + + virtual void DragEnter(TimelineViewMouseEvent *){} + virtual void DragMove(TimelineViewMouseEvent *){} + virtual void DragLeave(QDragLeaveEvent *){} + virtual void DragDrop(TimelineViewMouseEvent *){} + + TimelineWidget* parent(); + + static olive::timeline::MovementMode FlipTrimMode(const olive::timeline::MovementMode& trim_mode); + + const QGraphicsView::DragMode& drag_mode(); + + bool enable_default_behavior(); + + protected: + void set_drag_mode(const QGraphicsView::DragMode& mode); + + void set_enable_default_behavior(bool enable); + + /** + * @brief Retrieve the QGraphicsItem at a particular scene position + * + * Requires a float-based scene position. If you have a screen position, use GetScenePos() first to convert it to a + * scene position + */ + TimelineViewBlockItem* GetItemAtScenePos(const TimelineCoordinate &coord); + + /** + * @brief Validates Ghosts that are moving horizontally (time-based) + * + * Validation is the process of ensuring that whatever movements the user is making are "valid" and "legal". This + * function's validation ensures that no Ghost's in point ends up in a negative timecode. + */ + rational ValidateFrameMovement(rational movement, const QVector ghosts); + + /** + * @brief Validates Ghosts that are moving vertically (track-based) + * + * This function's validation ensures that no Ghost's track ends up in a negative (non-existent) track. + */ + int ValidateTrackMovement(int movement, const QVector ghosts); + + enum SnapPoints { + kSnapToClips = 0x1, + kSnapToPlayhead = 0x2, + kSnapAll = 0xFF + }; + + /** + * @brief Snaps point `start_point` that is moving by `movement` to currently existing clips + */ + bool SnapPoint(QList start_times, rational *movement, int snap_points = kSnapAll); + + QList snap_points_; + + bool dragging_; + + TimelineCoordinate drag_start_; + + private: + TimelineWidget* parent_; + + QGraphicsView::DragMode drag_mode_; + + bool enable_default_behavior_; + + }; + + class PointerTool : public Tool + { + public: + PointerTool(TimelineWidget* parent); + + virtual void MousePress(TimelineViewMouseEvent *event) override; + virtual void MouseMove(TimelineViewMouseEvent *event) override; + virtual void MouseRelease(TimelineViewMouseEvent *event) override; + protected: + void SetMovementAllowed(bool allowed); + void SetTrackMovementAllowed(bool allowed); + void SetTrimmingAllowed(bool allowed); + virtual void MouseReleaseInternal(TimelineViewMouseEvent *event); + virtual rational FrameValidateInternal(rational time_movement, const QVector &ghosts); + + virtual void InitiateGhosts(TimelineViewBlockItem* clicked_item, + olive::timeline::MovementMode trim_mode, + bool allow_gap_trimming); + + TimelineViewGhostItem* AddGhostFromBlock(Block *block, const TrackReference& track, olive::timeline::MovementMode mode); + + TimelineViewGhostItem* AddGhostFromNull(const rational& in, const rational& out, const TrackReference& track, olive::timeline::MovementMode mode); + + /** + * @brief Validates Ghosts that are getting their in points trimmed + * + * Assumes ghost->data() is a Block. Ensures no Ghost's in point becomes a negative timecode. Also ensures no + * Ghost's length becomes 0 or negative. + */ + rational ValidateInTrimming(rational movement, const QVector ghosts, bool prevent_overwriting); + + /** + * @brief Validates Ghosts that are getting their out points trimmed + * + * Assumes ghost->data() is a Block. Ensures no Ghost's in point becomes a negative timecode. Also ensures no + * Ghost's length becomes 0 or negative. + */ + rational ValidateOutTrimming(rational movement, const QVector ghosts, bool prevent_overwriting); + + virtual void ProcessDrag(const TimelineCoordinate &mouse_pos); + private: + void InitiateDrag(const TimelineCoordinate &mouse_pos); + + void AddGhostInternal(TimelineViewGhostItem* ghost, olive::timeline::MovementMode mode); + + QList GetSelectedClips(); + + bool IsClipTrimmable(TimelineViewBlockItem* clip, + const QList& items, + const olive::timeline::MovementMode& mode); + + TrackReference track_start_; + bool movement_allowed_; + bool trimming_allowed_; + bool track_movement_allowed_; + }; + + class ImportTool : public Tool + { + public: + ImportTool(TimelineWidget* parent); + + virtual void DragEnter(TimelineViewMouseEvent *event) override; + virtual void DragMove(TimelineViewMouseEvent *event) override; + virtual void DragLeave(QDragLeaveEvent *event) override; + virtual void DragDrop(TimelineViewMouseEvent *event) override; + private: + int import_pre_buffer_; + }; + + class RazorTool : public Tool + { + public: + RazorTool(TimelineWidget* parent); + + virtual void MousePress(TimelineViewMouseEvent *event); + virtual void MouseMove(TimelineViewMouseEvent *event); + virtual void MouseRelease(TimelineViewMouseEvent *event); + + private: + QVector split_tracks_; + }; + + class RippleTool : public PointerTool + { + public: + RippleTool(TimelineWidget* parent); + protected: + virtual void MouseReleaseInternal(TimelineViewMouseEvent *event) override; + virtual rational FrameValidateInternal(rational time_movement, const QVector& ghosts) override; + + virtual void InitiateGhosts(TimelineViewBlockItem* clicked_item, + olive::timeline::MovementMode trim_mode, + bool allow_gap_trimming) override; + }; + + class RollingTool : public PointerTool + { + public: + RollingTool(TimelineWidget* parent); + + protected: + virtual void MouseReleaseInternal(TimelineViewMouseEvent *event) override; + virtual rational FrameValidateInternal(rational time_movement, const QVector& ghosts) override; + + virtual void InitiateGhosts(TimelineViewBlockItem* clicked_item, + olive::timeline::MovementMode trim_mode, + bool allow_gap_trimming) override; + }; + + class SlideTool : public PointerTool + { + public: + SlideTool(TimelineWidget* parent); + + protected: + virtual void MouseReleaseInternal(TimelineViewMouseEvent *event) override; + virtual rational FrameValidateInternal(rational time_movement, const QVector& ghosts) override; + virtual void InitiateGhosts(TimelineViewBlockItem* clicked_item, + olive::timeline::MovementMode trim_mode, + bool allow_gap_trimming) override; + }; + + class SlipTool : public PointerTool + { + public: + SlipTool(TimelineWidget* parent); + + protected: + virtual void ProcessDrag(const TimelineCoordinate &mouse_pos) override; + virtual void MouseReleaseInternal(TimelineViewMouseEvent *event) override; + }; + + class HandTool : public Tool + { + public: + HandTool(TimelineWidget* parent); + + private: + QPoint screen_drag_start_; + QPoint scrollbar_start_; + }; + + class ZoomTool : public Tool + { + public: + ZoomTool(TimelineWidget* parent); + + virtual void MousePress(TimelineViewMouseEvent *event); + virtual void MouseMove(TimelineViewMouseEvent *event); + virtual void MouseRelease(TimelineViewMouseEvent *event); + }; + + Tool* GetActiveTool(); + + QVector< std::shared_ptr > tools_; + + std::shared_ptr import_tool_; + + Tool* active_tool_; + + void ClearGhosts(); + + bool HasGhosts(); + + QVector ghost_items_; + + QMap block_items_; + void RippleEditTo(olive::timeline::MovementMode mode, bool insert_gaps); void SetTimeAndSignal(const int64_t& t); + TrackOutput* GetTrackFromReference(const TrackReference& ref); + QList views_; TimeRuler* ruler_; - double scale_; - TimelineOutput* timeline_node_; - rational timebase_; - int64_t playhead_; QScrollBar* horizontal_scroll_; + int GetTrackY(const TrackReference& ref); + int GetTrackHeight(const TrackReference& ref); + + void CenterOn(qreal scene_pos); + private slots: void SetScale(double scale); @@ -81,6 +332,19 @@ private slots: void UpdateTimelineLength(const rational& length); + void ViewMousePressed(TimelineViewMouseEvent* event); + void ViewMouseMoved(TimelineViewMouseEvent* event); + void ViewMouseReleased(TimelineViewMouseEvent* event); + void ViewMouseDoubleClicked(TimelineViewMouseEvent* event); + + void ViewDragEntered(TimelineViewMouseEvent* event); + void ViewDragMoved(TimelineViewMouseEvent* event); + void ViewDragLeft(QDragLeaveEvent* event); + void ViewDragDropped(TimelineViewMouseEvent* event); + + void AddBlock(Block* block, TrackReference track); + void RemoveBlock(Block* block); + }; #endif // TIMELINEWIDGET_H