diff --git a/app/core.cpp b/app/core.cpp index a127c0cfd..dd0638099 100644 --- a/app/core.cpp +++ b/app/core.cpp @@ -227,6 +227,7 @@ void Core::CreateNewFolder() #include "node/processor/renderer/renderer.h" #include "panel/panelmanager.h" #include "panel/node/node.h" +#include "panel/timeline/timeline.h" #include "panel/viewer/viewer.h" // End test code @@ -311,7 +312,7 @@ void Core::CreateNewSequence() NodeParam::ConnectEdge(tb->length_output(), rp->length_input()); vo->AttachViewer(olive::panel_focus_manager->MostRecentlyFocused()); - tb->AttachTimeline(olive::panel_focus_manager->MostRecentlyFocused()); + olive::panel_focus_manager->MostRecentlyFocused()->ConnectTimelineNode(tb); olive::panel_focus_manager->MostRecentlyFocused()->SetGraph(new_sequence.get()); olive::undo_stack.push(aic); diff --git a/app/node/output/timeline/timeline.cpp b/app/node/output/timeline/timeline.cpp index 12aff1885..0011c221f 100644 --- a/app/node/output/timeline/timeline.cpp +++ b/app/node/output/timeline/timeline.cpp @@ -25,9 +25,9 @@ #include "node/blend/alphaover/alphaover.h" #include "node/block/gap/gap.h" #include "node/graph.h" +#include "panel/timeline/timeline.h" -TimelineOutput::TimelineOutput() : - attached_timeline_(nullptr) +TimelineOutput::TimelineOutput() { track_input_ = new NodeInput("track_in"); track_input_->add_data_input(NodeParam::kTrack); @@ -61,43 +61,6 @@ QString TimelineOutput::Description() return tr("Node for communicating between a Timeline panel and the node graph."); } -void TimelineOutput::AttachTimeline(TimelinePanel *timeline) -{ - if (attached_timeline_ != nullptr) { - TimelineView* view = attached_timeline_->view(); - - //disconnect(view, SIGNAL(RequestInsertBlockAtIndex(Block*, int)), this, SLOT(InsertBlockAtIndex(Block*, int))); - disconnect(view, SIGNAL(RequestPlaceBlock(Block*, rational, int)), this, SLOT(PlaceBlock(Block*, rational, int))); - disconnect(view, SIGNAL(RequestReplaceBlock(Block*, Block*, int)), this, SLOT(ReplaceBlock(Block*, Block*, int))); - disconnect(view, SIGNAL(RequestSplitAtTime(rational, int)), this, SLOT(SplitAtTime(rational, int))); - disconnect(view, SIGNAL(RequestRippleBlocks(QList, rational, olive::timeline::MovementMode)), this, SLOT(RippleBlocks(QList, rational, olive::timeline::MovementMode))); - - // Remove existing UI objects from TimelinePanel - attached_timeline_->Clear(); - } - - attached_timeline_ = timeline; - - if (attached_timeline_ != nullptr) { - // FIXME: TEST CODE ONLY - attached_timeline_->SetTimebase(rational(1001, 30000)); - // END TEST CODE - - foreach (TrackOutput* track, track_cache_) { - // Defer to the track to make all the block UI items necessary - track->GenerateBlockWidgets(); - } - - TimelineView* view = attached_timeline_->view(); - - //connect(view, SIGNAL(RequestInsertBlockAtIndex(Block*, int)), this, SLOT(InsertBlockAtIndex(Block*, int))); - connect(view, SIGNAL(RequestPlaceBlock(Block*, rational, int)), this, SLOT(PlaceBlock(Block*, rational, int))); - connect(view, SIGNAL(RequestReplaceBlock(Block*, Block*, int)), this, SLOT(ReplaceBlock(Block*, Block*, int))); - connect(view, SIGNAL(RequestSplitAtTime(rational, int)), this, SLOT(SplitAtTime(rational, int))); - connect(view, SIGNAL(RequestRippleBlocks(QList, rational, olive::timeline::MovementMode)), this, SLOT(RippleBlocks(QList, rational, olive::timeline::MovementMode))); - } -} - NodeInput *TimelineOutput::track_input() { return track_input_; @@ -108,6 +71,11 @@ NodeOutput *TimelineOutput::length_output() return length_output_; } +const QVector &TimelineOutput::Tracks() +{ + return track_cache_; +} + QVariant TimelineOutput::Value(NodeOutput *output, const rational &time) { if (output == length_output_) { @@ -126,11 +94,6 @@ QVariant TimelineOutput::Value(NodeOutput *output, const rational &time) return 0; } -int TimelineOutput::GetTrackIndex(TrackOutput *track) -{ - return track_cache_.indexOf(track); -} - rational TimelineOutput::GetSequenceLength() { rational length = 0; @@ -158,11 +121,13 @@ void TimelineOutput::AttachTrack(TrackOutput *track) connect(current_track, SIGNAL(BlockAdded(Block*)), this, SLOT(TrackAddedBlock(Block*))); connect(current_track, SIGNAL(BlockRemoved(Block*)), this, SLOT(TrackRemovedBlock(Block*))); + current_track->SetIndex(track_cache_.size()); + track_cache_.append(current_track); // This function must be called after the track is added to track_cache_, since it uses track_cache_ to determine // the track's index - current_track->GenerateBlockWidgets(); + emit TrackAdded(current_track); current_track = current_track->next_track(); } @@ -174,7 +139,9 @@ void TimelineOutput::DetachTrack(TrackOutput *track) // Traverse through Tracks uncaching and disconnecting them while (current_track != nullptr) { - current_track->DestroyBlockWidgets(); + emit TrackRemoved(current_track); + + current_track->SetIndex(-1); disconnect(current_track, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SLOT(TrackEdgeAdded(NodeEdgePtr))); disconnect(current_track, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SLOT(TrackEdgeRemoved(NodeEdgePtr))); @@ -191,9 +158,7 @@ void TimelineOutput::SetTimebase(const rational &timebase) { timebase_ = timebase; - if (attached_timeline_ != nullptr) { - attached_timeline_->SetTimebase(timebase_); - } + emit TimebaseChanged(timebase_); } void TimelineOutput::AddTrack() @@ -243,9 +208,8 @@ void TimelineOutput::TrackConnectionAdded(NodeEdgePtr edge) AttachTrack(attached_track()); - if (attached_timeline_ != nullptr) { - attached_timeline_->SetTimebase(timebase_); - } + // FIXME: Is this necessary? + emit TimebaseChanged(timebase_); } void TimelineOutput::TrackConnectionRemoved(NodeEdgePtr edge) @@ -256,23 +220,17 @@ void TimelineOutput::TrackConnectionRemoved(NodeEdgePtr edge) DetachTrack(ValueToPtr(edge->output()->get_value(0))); - if (attached_timeline_ != nullptr) { - attached_timeline_->Clear(); - } + emit TimelineCleared(); } void TimelineOutput::TrackAddedBlock(Block *block) { - if (attached_timeline_ != nullptr) { - attached_timeline_->view()->AddBlock(block, GetTrackIndex(static_cast(sender()))); - } + emit BlockAdded(block, static_cast(sender())->Index()); } void TimelineOutput::TrackRemovedBlock(Block *block) { - if (attached_timeline_ != nullptr) { - attached_timeline_->view()->RemoveBlock(block); - } + emit BlockRemoved(block); } void TimelineOutput::TrackEdgeAdded(NodeEdgePtr edge) diff --git a/app/node/output/timeline/timeline.h b/app/node/output/timeline/timeline.h index d9685eb4a..5437dfc5d 100644 --- a/app/node/output/timeline/timeline.h +++ b/app/node/output/timeline/timeline.h @@ -21,9 +21,9 @@ #ifndef TIMELINEOUTPUT_H #define TIMELINEOUTPUT_H +#include "common/timelinecommon.h" #include "node/block/block.h" #include "node/output/track/track.h" -#include "panel/timeline/timeline.h" /** * @brief Node that represents the end of the Timeline as well as a time traversal Node @@ -39,46 +39,15 @@ public: virtual QString Category() override; virtual QString Description() override; - void AttachTimeline(TimelinePanel* timeline); - void SetTimebase(const rational& timebase); NodeInput* track_input(); NodeOutput* length_output(); -protected: - virtual QVariant Value(NodeOutput* output, const rational& time) override; + const QVector& Tracks(); -private: - int GetTrackIndex(TrackOutput* track); - - rational GetSequenceLength(); - - TrackOutput* attached_track(); - - void AttachTrack(TrackOutput *track); - - void DetachTrack(TrackOutput* track); - - void AddTrack(); - - static TrackOutput* TrackFromBlock(Block* block); - - TimelinePanel* attached_timeline_; - - NodeInput* track_input_; - - NodeOutput* length_output_; - - /** - * @brief A cache of connected Tracks - */ - QVector track_cache_; - - rational timebase_; - -private slots: +public slots: /** * @brief Slot for when the track connection is added */ @@ -134,6 +103,46 @@ private slots: void RippleBlocks(QList blocks, rational ripple_length, olive::timeline::MovementMode mode); +signals: + void TimebaseChanged(const rational &timebase); + + void TimelineCleared(); + + void BlockAdded(Block* block, int index); + + void BlockRemoved(Block* block); + + void TrackAdded(TrackOutput* track); + + void TrackRemoved(TrackOutput* track); + +protected: + virtual QVariant Value(NodeOutput* output, const rational& time) override; + +private: + rational GetSequenceLength(); + + TrackOutput* attached_track(); + + void AttachTrack(TrackOutput *track); + + void DetachTrack(TrackOutput* track); + + void AddTrack(); + + static TrackOutput* TrackFromBlock(Block* block); + + NodeInput* track_input_; + + NodeOutput* length_output_; + + /** + * @brief A cache of connected Tracks + */ + QVector track_cache_; + + rational timebase_; + }; #endif // TIMELINEOUTPUT_H diff --git a/app/node/output/track/track.cpp b/app/node/output/track/track.cpp index 51c8c2e42..f4c5895e0 100644 --- a/app/node/output/track/track.cpp +++ b/app/node/output/track/track.cpp @@ -27,7 +27,8 @@ TrackOutput::TrackOutput() : current_block_(this), - block_invalidate_cache_stack_(0) + block_invalidate_cache_stack_(0), + index_(-1) { track_input_ = new NodeInput("track_in"); track_input_->add_data_input(NodeParam::kTrack); @@ -107,6 +108,16 @@ void TrackOutput::Refresh() qDebug() << "Refreshed with in point" << in().toDouble() << "(from connected block" << previous() << ")"; } +const int &TrackOutput::Index() +{ + return index_; +} + +void TrackOutput::SetIndex(const int &index) +{ + index_ = index; +} + QList TrackOutput::RunDependencies(NodeOutput* output, const rational &time) { QList deps; @@ -122,20 +133,6 @@ QList TrackOutput::RunDependencies(NodeOutput* output, const rat return deps; } -void TrackOutput::GenerateBlockWidgets() -{ - foreach (Block* block, block_cache_) { - emit BlockAdded(block); - } -} - -void TrackOutput::DestroyBlockWidgets() -{ - foreach (Block* block, block_cache_) { - emit BlockRemoved(block); - } -} - TrackOutput *TrackOutput::next_track() { return ValueToPtr(track_input_->get_value(0)); @@ -163,6 +160,11 @@ Block *TrackOutput::NearestBlockAfter(const rational &time) return nullptr; } +const QVector &TrackOutput::Blocks() +{ + return block_cache_; +} + void TrackOutput::InvalidateCache(const rational &start_range, const rational &end_range, NodeInput *from) { // We intercept IC signals from Blocks since we may be performing several options and they may over-signal diff --git a/app/node/output/track/track.h b/app/node/output/track/track.h index 1a22cd72e..6bfe6aafb 100644 --- a/app/node/output/track/track.h +++ b/app/node/output/track/track.h @@ -22,7 +22,6 @@ #define TRACKOUTPUT_H #include "node/block/block.h" -#include "panel/timeline/timeline.h" /** * @brief A time traversal Node for sorting through one channel/track of Blocks @@ -46,15 +45,14 @@ public: virtual void Refresh() override; + const int& Index(); + void SetIndex(const int& index); + /** * @brief Override swaps "attached block" with "current block" */ virtual QList RunDependencies(NodeOutput* param, const rational& time) override; - void GenerateBlockWidgets(); - - void DestroyBlockWidgets(); - TrackOutput* next_track(); NodeInput* track_input(); @@ -63,6 +61,8 @@ public: Block* NearestBlockAfter(const rational& time); + const QVector& Blocks(); + virtual void InvalidateCache(const rational& start_range, const rational& end_range, NodeInput* from = nullptr) override; /** @@ -203,6 +203,8 @@ private: int block_invalidate_cache_stack_; + int index_; + private slots: }; diff --git a/app/panel/timeline/timeline.cpp b/app/panel/timeline/timeline.cpp index ab120be4c..ebb8875a7 100644 --- a/app/panel/timeline/timeline.cpp +++ b/app/panel/timeline/timeline.cpp @@ -40,7 +40,8 @@ TimelinePanel::TimelinePanel(QWidget *parent) : layout->addWidget(view_); connect(view_->horizontalScrollBar(), SIGNAL(valueChanged(int)), ruler_, SLOT(SetScroll(int))); - connect(view_, SIGNAL(UserSetScale(double)), this, SLOT(SetScale(double))); + connect(view_, SIGNAL(ScaleChanged(double)), this, SLOT(SetScale(double))); + connect(view_, SIGNAL(TimebaseChanged(const rational&)), this, SLOT(SetTimebase(const rational&))); connect(ruler_, SIGNAL(TimeChanged(const int64_t&)), view_, SLOT(SetTime(const int64_t&))); // FIXME: Magic number @@ -67,6 +68,16 @@ TimelineView *TimelinePanel::view() return view_; } +void TimelinePanel::ConnectTimelineNode(TimelineOutput *node) +{ + view_->ConnectTimelineNode(node); +} + +void TimelinePanel::DisconnectTimelineNode() +{ + view_->DisconnectTimelineNode(); +} + void TimelinePanel::ZoomIn() { SetScale(scale_ * 2); diff --git a/app/panel/timeline/timeline.h b/app/panel/timeline/timeline.h index a6120b355..8182762b8 100644 --- a/app/panel/timeline/timeline.h +++ b/app/panel/timeline/timeline.h @@ -33,14 +33,19 @@ public: void Clear(); - void SetTimebase(const rational& timebase); - TimelineView* view(); + void ConnectTimelineNode(TimelineOutput* node); + + void DisconnectTimelineNode(); + virtual void ZoomIn() override; virtual void ZoomOut() override; +public slots: + void SetTimebase(const rational& timebase); + protected: virtual void changeEvent(QEvent* e) override; diff --git a/app/widget/timelineview/timelineview.cpp b/app/widget/timelineview/timelineview.cpp index a527b72d8..eb49a72cd 100644 --- a/app/widget/timelineview/timelineview.cpp +++ b/app/widget/timelineview/timelineview.cpp @@ -40,6 +40,7 @@ TimelineView::TimelineView(QWidget *parent) : razor_tool_(this), hand_tool_(this), zoom_tool_(this), + timeline_node_(nullptr), playhead_(0) { setScene(&scene_); @@ -102,6 +103,20 @@ void TimelineView::RemoveBlock(Block *block) clip_items_.remove(block); } +void TimelineView::AddTrack(TrackOutput *track) +{ + foreach (Block* b, track->Blocks()) { + AddBlock(b, track->Index()); + } +} + +void TimelineView::RemoveTrack(TrackOutput *track) +{ + foreach (Block* b, track->Blocks()) { + RemoveBlock(b); + } +} + void TimelineView::SetScale(const double &scale) { scale_ = scale; @@ -142,6 +157,50 @@ void TimelineView::Clear() clip_items_.clear(); } +void TimelineView::ConnectTimelineNode(TimelineOutput *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*))); + + Clear(); + } + + timeline_node_ = node; + + if (timeline_node_ != nullptr) { + qDebug() << "Connecting to" << node; + + // FIXME: TEST CODE ONLY + SetTimebase(rational(1001, 30000)); + emit TimebaseChanged(rational(1001, 30000)); + // END TEST CODE + + 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*))); + + foreach (TrackOutput* track, timeline_node_->Tracks()) { + // Defer to the track to make all the block UI items necessary + AddTrack(track); + } + } +} + +void TimelineView::DisconnectTimelineNode() +{ + ConnectTimelineNode(nullptr); +} + void TimelineView::SetTime(const int64_t time) { playhead_ = time; diff --git a/app/widget/timelineview/timelineview.h b/app/widget/timelineview/timelineview.h index b1bb6f74c..7c399b863 100644 --- a/app/widget/timelineview/timelineview.h +++ b/app/widget/timelineview/timelineview.h @@ -28,6 +28,7 @@ #include #include "node/block/clip/clip.h" +#include "node/output/timeline/timeline.h" #include "timelineviewclipitem.h" #include "timelineviewghostitem.h" #include "timelineviewplayheaditem.h" @@ -43,28 +44,31 @@ class TimelineView : public QGraphicsView public: TimelineView(QWidget* parent); + void SetScale(const double& scale); + + void ConnectTimelineNode(TimelineOutput* node); + + void DisconnectTimelineNode(); + +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 RemoveBlocksOfTrack(Block* block); + void AddTrack(TrackOutput* track); - void SetScale(const double& scale); - - void SetTimebase(const rational& timebase); - - void Clear(); - -public slots: - void SetTime(const int64_t time); + void RemoveTrack(TrackOutput* track); signals: - void RequestPlaceBlock(Block* block, rational start, int track); - void RequestReplaceBlock(Block* old, Block* replace, int track); - void RequestSplitAtTime(rational time, int track); - void RequestRippleBlocks(QList blocks, rational length, olive::timeline::MovementMode mode); + void ScaleChanged(double scale); - void UserSetScale(double scale); + void TimebaseChanged(const rational& timebase); protected: virtual void mousePressEvent(QMouseEvent *event) override; @@ -261,6 +265,8 @@ private: HandTool hand_tool_; ZoomTool zoom_tool_; + TimelineOutput* timeline_node_; + void AddGhost(TimelineViewGhostItem* ghost); bool HasGhosts(); diff --git a/app/widget/timelineview/tool/import.cpp b/app/widget/timelineview/tool/import.cpp index a4435b07b..f84d18131 100644 --- a/app/widget/timelineview/tool/import.cpp +++ b/app/widget/timelineview/tool/import.cpp @@ -188,7 +188,7 @@ void TimelineView::ImportTool::DragDrop(QDropEvent *event) if (event->keyboardModifiers() & Qt::ControlModifier) { //emit parent()->RequestInsertBlockAtTime(clip, ghost->GetAdjustedIn()); } else { - emit parent()->RequestPlaceBlock(clip, ghost->GetAdjustedIn(), ghost->Track()); + parent()->timeline_node_->PlaceBlock(clip, ghost->GetAdjustedIn(), ghost->Track()); } } diff --git a/app/widget/timelineview/tool/pointer.cpp b/app/widget/timelineview/tool/pointer.cpp index 9ef86ad72..5bdc13933 100644 --- a/app/widget/timelineview/tool/pointer.cpp +++ b/app/widget/timelineview/tool/pointer.cpp @@ -121,7 +121,7 @@ void TimelineView::PointerTool::MouseReleaseInternal(QMouseEvent *event) gap->setParent(&block_memory_manager); gap->set_length(b->length()); - emit parent()->RequestReplaceBlock(b, gap, ghost->Track()); + parent()->timeline_node_->ReplaceBlock(b, gap, ghost->Track()); } // Now we place the clips back in the timeline where the user moved them. It's legal for them to overwrite parts or @@ -140,7 +140,7 @@ void TimelineView::PointerTool::MouseReleaseInternal(QMouseEvent *event) b->set_length(ghost->AdjustedLength()); } - emit parent()->RequestPlaceBlock(b, ghost->GetAdjustedIn(), ghost->GetAdjustedTrack()); + parent()->timeline_node_->PlaceBlock(b, ghost->GetAdjustedIn(), ghost->GetAdjustedTrack()); } } diff --git a/app/widget/timelineview/tool/razor.cpp b/app/widget/timelineview/tool/razor.cpp index e68a4501a..5d7a04736 100644 --- a/app/widget/timelineview/tool/razor.cpp +++ b/app/widget/timelineview/tool/razor.cpp @@ -45,7 +45,7 @@ void TimelineView::RazorTool::MouseMove(QMouseEvent *event) // Split at the current cursor track int split_track = parent()->SceneToTrack(current_scene_pos.y()); - emit parent()->RequestSplitAtTime(split_time, split_track); + parent()->timeline_node_->SplitAtTime(split_time, split_track); } void TimelineView::RazorTool::MouseRelease(QMouseEvent *event) diff --git a/app/widget/timelineview/tool/ripple.cpp b/app/widget/timelineview/tool/ripple.cpp index ffc237d68..5a785fcae 100644 --- a/app/widget/timelineview/tool/ripple.cpp +++ b/app/widget/timelineview/tool/ripple.cpp @@ -53,7 +53,7 @@ void TimelineView::RippleTool::MouseReleaseInternal(QMouseEvent *event) blocks_to_ripple.append(b); } - emit parent()->RequestRippleBlocks(blocks_to_ripple, ripple_length, movement_mode); + parent()->timeline_node_->RippleBlocks(blocks_to_ripple, ripple_length, movement_mode); } rational TimelineView::RippleTool::FrameValidateInternal(rational time_movement, QVector ghosts) diff --git a/app/widget/timelineview/tool/zoom.cpp b/app/widget/timelineview/tool/zoom.cpp index 5da184200..6380a2663 100644 --- a/app/widget/timelineview/tool/zoom.cpp +++ b/app/widget/timelineview/tool/zoom.cpp @@ -37,11 +37,16 @@ void TimelineView::ZoomTool::MouseMove(QMouseEvent *event) void TimelineView::ZoomTool::MouseRelease(QMouseEvent *event) { + double scale = parent()->scale_; + if (event->modifiers() & Qt::AltModifier) { // Zoom out if the user clicks while holding Alt - emit parent()->UserSetScale(parent()->scale_ * 0.5); + scale *= 0.5; } else { // Otherwise zoom in - emit parent()->UserSetScale(parent()->scale_ * 2); + scale *= 2; } + + parent()->SetScale(scale); + emit parent()->ScaleChanged(scale); }