base support for multiple timeline sections

This commit is contained in:
itsmattkc
2019-10-11 18:26:56 +11:00
parent e9f5d0d248
commit 1ded30c1d9
18 changed files with 178 additions and 208 deletions
-1
View File
@@ -20,6 +20,5 @@ 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
)
+16 -3
View File
@@ -45,6 +45,8 @@ TimelineOutput::TimelineOutput()
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*)));
connect(list, SIGNAL(TrackAdded(TrackOutput*)), this, SLOT(TrackListAddedTrack(TrackOutput*)));
connect(list, SIGNAL(TrackRemoved(TrackOutput*)), this, SIGNAL(TrackRemoved(TrackOutput*)));
}
length_output_ = new NodeOutput("length_out");
@@ -87,6 +89,11 @@ const rational &TimelineOutput::timeline_length()
return length_;
}
const rational &TimelineOutput::Timebase()
{
return timebase_;
}
QVariant TimelineOutput::Value(NodeOutput *output, const rational &time)
{
if (output == length_output_) {
@@ -136,9 +143,9 @@ void TimelineOutput::UpdateLength(const rational &length)
void TimelineOutput::SetTimebase(const rational &timebase)
{
foreach (TrackList* list, track_lists_) {
list->SetTimebase(timebase);
}
timebase_ = timebase;
emit TimebaseChanged(timebase_);
}
NodeInput *TimelineOutput::track_input(TrackType type)
@@ -156,3 +163,9 @@ void TimelineOutput::TrackListAddedBlock(Block *block, int index)
TrackType type = static_cast<TrackList*>(sender())->TrackType();
emit BlockAdded(block, TrackReference(type, index));
}
void TimelineOutput::TrackListAddedTrack(TrackOutput *track)
{
TrackType type = static_cast<TrackList*>(sender())->TrackType();
emit TrackAdded(track, type);
}
+11 -2
View File
@@ -25,8 +25,8 @@
#include "node/block/block.h"
#include "node/output/track/track.h"
#include "timeline/trackreference.h"
#include "timeline/tracktypes.h"
#include "tracklist.h"
#include "tracktypes.h"
/**
* @brief Node that represents the end of the Timeline as well as a time traversal Node
@@ -52,15 +52,20 @@ public:
const rational& timeline_length();
const rational& Timebase();
void SetTimebase(const rational &timebase);
signals:
void LengthChanged(const rational& length);
void TimebaseChanged(const rational &timebase);
void BlockAdded(Block* block, TrackReference track);
void BlockRemoved(Block* block);
void TrackAdded(TrackOutput* track, TrackType type);
void TrackRemoved(TrackOutput* track);
protected:
virtual QVariant Value(NodeOutput* output, const rational& time) override;
@@ -75,6 +80,8 @@ private:
rational length_;
rational timebase_;
private slots:
void UpdateTrackCache();
@@ -82,6 +89,8 @@ private slots:
void TrackListAddedBlock(Block* block, int index);
void TrackListAddedTrack(TrackOutput* track);
};
#endif // TIMELINEOUTPUT_H
+2 -17
View File
@@ -50,6 +50,7 @@ void TrackList::AttachTrack(TrackOutput *track)
connect(current_track, SIGNAL(Refreshed()), this, SLOT(UpdateTotalLength()));
current_track->SetIndex(track_cache_.size());
current_track->set_track_type(type_);
track_cache_.append(current_track);
emit TrackListChanged();
@@ -73,6 +74,7 @@ void TrackList::DetachTrack(TrackOutput *track)
emit TrackRemoved(current_track);
current_track->SetIndex(-1);
current_track->set_track_type(kTrackTypeNone);
disconnect(current_track, SIGNAL(EdgeAdded(NodeEdgePtr)), this, SLOT(TrackEdgeAdded(NodeEdgePtr)));
disconnect(current_track, SIGNAL(EdgeRemoved(NodeEdgePtr)), this, SLOT(TrackEdgeRemoved(NodeEdgePtr)));
@@ -109,18 +111,6 @@ TrackOutput *TrackList::TrackAt(int index)
return track_cache_.at(index);
}
const rational &TrackList::Timebase()
{
return timebase_;
}
void TrackList::SetTimebase(const rational &timebase)
{
timebase_ = timebase;
emit TimebaseChanged(timebase_);
}
const rational &TrackList::TrackLength()
{
return total_length_;
@@ -178,9 +168,6 @@ void TrackList::TrackConnectionAdded(NodeEdgePtr edge)
}
AttachTrack(attached_track());
// FIXME: Is this necessary?
emit TimebaseChanged(timebase_);
}
void TrackList::TrackConnectionRemoved(NodeEdgePtr edge)
@@ -190,8 +177,6 @@ void TrackList::TrackConnectionRemoved(NodeEdgePtr edge)
}
DetachTrack(Node::ValueToPtr<TrackOutput>(edge->output()->get_value(0)));
emit TimelineCleared();
}
void TrackList::TrackEdgeAdded(NodeEdgePtr edge)
+1 -11
View File
@@ -25,7 +25,7 @@
#include "node/graph.h"
#include "node/output/track/track.h"
#include "tracktypes.h"
#include "timeline/tracktypes.h"
class TimelineOutput;
@@ -48,10 +48,6 @@ public:
void RemoveTrack();
const rational& Timebase();
void SetTimebase(const rational& timebase);
const rational& TrackLength();
const enum TrackType& TrackType();
@@ -97,10 +93,6 @@ signals:
void TrackListChanged();
void TimelineCleared();
void TimebaseChanged(const rational &timebase);
void LengthChanged(const rational &length);
private:
@@ -111,8 +103,6 @@ private:
*/
QVector<TrackOutput*> track_cache_;
rational timebase_;
NodeInput* track_input_;
rational total_length_;
+11
View File
@@ -27,6 +27,7 @@
TrackOutput::TrackOutput() :
current_block_(this),
track_type_(kTrackTypeNone),
block_invalidate_cache_stack_(0),
index_(-1)
{
@@ -40,6 +41,16 @@ TrackOutput::TrackOutput() :
AddParameter(track_output_);
}
void TrackOutput::set_track_type(const TrackType &track_type)
{
track_type_ = track_type;
}
const TrackType& TrackOutput::track_type()
{
return track_type_;
}
Block::Type TrackOutput::type()
{
return kEnd;
+6
View File
@@ -22,6 +22,7 @@
#define TRACKOUTPUT_H
#include "node/block/block.h"
#include "timeline/tracktypes.h"
/**
* @brief A time traversal Node for sorting through one channel/track of Blocks
@@ -32,6 +33,9 @@ class TrackOutput : public Block
public:
TrackOutput();
const TrackType& track_type();
void set_track_type(const TrackType& track_type);
virtual Type type() override;
virtual Block* copy() override;
@@ -170,6 +174,8 @@ private:
NodeOutput* track_output_;
TrackType track_type_;
int block_invalidate_cache_stack_;
int index_;
+1
View File
@@ -20,5 +20,6 @@ set(OLIVE_SOURCES
timeline/timelinecoordinate.cpp
timeline/trackreference.h
timeline/trackreference.cpp
timeline/tracktypes.h
PARENT_SCOPE
)
+1 -1
View File
@@ -21,7 +21,7 @@
#ifndef TRACKREFERENCE_H
#define TRACKREFERENCE_H
#include "node/output/timeline/tracktypes.h"
#include "timeline/tracktypes.h"
class TrackReference
{
+3 -93
View File
@@ -33,11 +33,10 @@
#include "node/input/media/media.h"
#include "project/item/footage/footage.h"
TimelineView::TimelineView(Qt::Alignment vertical_alignment, QWidget *parent) :
TimelineView::TimelineView(const TrackType &type, Qt::Alignment vertical_alignment, QWidget *parent) :
QGraphicsView(parent),
timeline_node_(nullptr),
playhead_(0),
use_tracklist_length_directly_(true)
type_(type)
{
Q_ASSERT(vertical_alignment == Qt::AlignTop || vertical_alignment == Qt::AlignBottom);
setAlignment(Qt::AlignLeft | vertical_alignment);
@@ -57,20 +56,6 @@ TimelineView::TimelineView(Qt::Alignment vertical_alignment, QWidget *parent) :
SetScale(1.0);
}
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;
@@ -89,44 +74,6 @@ void TimelineView::SetTimebase(const rational &timebase)
viewport()->update();
}
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(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&)));
Clear();
}
timeline_node_ = node;
if (timeline_node_ != nullptr) {
SetTimebase(timeline_node_->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(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&)));
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::SelectAll()
{
QList<QGraphicsItem*> all_items = items();
@@ -145,11 +92,6 @@ void TimelineView::DeselectAll()
}
}
void TimelineView::SetUseTrackListLengthDirectly(bool use)
{
use_tracklist_length_directly_ = use;
}
void TimelineView::SetTime(const int64_t time)
{
playhead_ = time;
@@ -257,15 +199,6 @@ void TimelineView::drawForeground(QPainter *painter, const QRectF &rect)
}
}
TrackType TimelineView::ConnectedTrackType()
{
if (timeline_node_ != nullptr) {
return timeline_node_->TrackType();
}
return kTrackTypeNone;
}
Stream::Type TimelineView::TrackTypeToStreamType(TrackType track_type)
{
switch (track_type) {
@@ -290,7 +223,7 @@ TimelineCoordinate TimelineView::ScreenToCoordinate(const QPoint& pt)
TimelineCoordinate TimelineView::SceneToCoordinate(const QPointF& pt)
{
return TimelineCoordinate(SceneToTime(pt.x()), SceneToTrack(pt.y()));
return TimelineCoordinate(SceneToTime(pt.x()), TrackReference(type_, SceneToTrack(pt.y())));
}
int TimelineView::GetTrackY(int track_index)
@@ -316,13 +249,6 @@ int TimelineView::GetTrackHeight(int track_index)
return fontMetrics().height() * 3;
}
void TimelineView::AddGhost(TimelineViewGhostItem *ghost)
{
ghost->SetScale(scale_);
ghost_items_.append(ghost);
scene_.addItem(ghost);
}
int TimelineView::SceneToTrack(double y)
{
int track = -1;
@@ -351,15 +277,6 @@ rational TimelineView::GetPlayheadTime()
return rational(playhead_ * timebase().numerator(), timebase().denominator());
}
void TimelineView::BlockChanged()
{
TimelineViewRect* rect = block_items_[static_cast<Block*>(sender())];
if (rect != nullptr) {
rect->UpdateRect();
}
}
void TimelineView::UpdateSceneRect()
{
QRectF bounding_rect = scene_.itemsBoundingRect();
@@ -395,13 +312,6 @@ void TimelineView::UpdateSceneRect()
scene_.setSceneRect(bounding_rect);
}
void TimelineView::UpdateEndTimeFromTrackList(const rational &length)
{
if (use_tracklist_length_directly_) {
SetEndTime(length);
}
}
void TimelineView::SetEndTime(const rational &length)
{
end_item_->SetEndTime(length);
+4 -31
View File
@@ -46,20 +46,16 @@ class TimelineView : public QGraphicsView, public TimelineScaledObject
{
Q_OBJECT
public:
TimelineView(Qt::Alignment vertical_alignment = Qt::AlignTop, QWidget* parent = nullptr);
TimelineView(const TrackType& type,
Qt::Alignment vertical_alignment = Qt::AlignTop,
QWidget* parent = nullptr);
void SetScale(const double& scale);
void ConnectTimelineNode(TrackList* node);
void DisconnectTimelineNode();
void SelectAll();
void DeselectAll();
void SetUseTrackListLengthDirectly(bool use);
void SetEndTime(const rational& length);
int GetTrackY(int track_index);
@@ -70,15 +66,9 @@ public slots:
void SetTime(const int64_t time);
void AddTrack(TrackOutput* track);
void RemoveTrack(TrackOutput* track);
signals:
void ScaleChanged(double scale);
void TimebaseChanged(const rational& timebase);
void TimeChanged(const int64_t& time);
void MousePressed(TimelineViewMouseEvent* event);
@@ -113,10 +103,6 @@ private:
TimelineCoordinate ScreenToCoordinate(const QPoint& pt);
TimelineCoordinate SceneToCoordinate(const QPointF& pt);
TrackList* timeline_node_;
void AddGhost(TimelineViewGhostItem* ghost);
int SceneToTrack(double y);
void UserSetTime(const int64_t& time);
@@ -137,27 +123,14 @@ private:
QRect playhead_rect_;
bool use_tracklist_length_directly_;
TrackType type_;
private slots:
/**
* @brief Slot for when a Block node changes its parameters and the graphics need to update
*
* This slot does a static_cast on sender() to Block*, meaning all objects triggering this slot must be Blocks or
* derivatives.
*/
void BlockChanged();
/**
* @brief Slot called whenever the view resizes or the scene contents change to enforce minimum scene sizes
*/
void UpdateSceneRect();
/**
* @brief When the attached track list's end frame changes, update the graphical representation here
*/
void UpdateEndTimeFromTrackList(const rational& length);
};
#endif // TIMELINEVIEW_H
@@ -172,7 +172,7 @@ rational TimelineViewGhostItem::GetAdjustedMediaIn() const
TrackReference TimelineViewGhostItem::GetAdjustedTrack() const
{
return track_ + track_adj_;
return TrackReference(track_.type(), track_.index() + track_adj_);
}
const olive::timeline::MovementMode &TimelineViewGhostItem::mode() const
+14 -8
View File
@@ -95,6 +95,10 @@ void TimelineWidget::ImportTool::DragEnter(TimelineViewMouseEvent *event)
// If the Item is Footage, we can create a Ghost from it
Footage* footage = static_cast<Footage*>(item);
// Each stream is offset by one track per track "type", we keep track of them in this vector
QVector<int> track_offsets(kTrackTypeCount);
track_offsets.fill(drag_start_.GetTrack().index());
rational footage_duration;
// Loop through all streams in footage
@@ -119,6 +123,10 @@ void TimelineWidget::ImportTool::DragEnter(TimelineViewMouseEvent *event)
ghost->SetIn(ghost_start);
ghost->SetOut(ghost_start + footage_duration);
ghost->SetTrack(TrackReference(track_type, track_offsets.at(track_type)));
// Increment track count for this track type
track_offsets[track_type]++;
snap_points_.append(ghost->In());
snap_points_.append(ghost->Out());
@@ -145,10 +153,7 @@ void TimelineWidget::ImportTool::DragMove(TimelineViewMouseEvent *event)
{
if (parent()->HasGhosts()) {
rational time_movement = event->GetCoordinates().GetFrame() - drag_start_.GetFrame();
const TrackReference& ghost_track = event->GetCoordinates().GetTrack();
int ghost_y = parent()->GetTrackY(ghost_track);
int ghost_height = parent()->GetTrackHeight(ghost_track);
int track_movement = event->GetCoordinates().GetTrack().index() - drag_start_.GetTrack().index();
// If snapping is enabled, check for snap points
if (olive::core.snapping()) {
@@ -156,6 +161,7 @@ void TimelineWidget::ImportTool::DragMove(TimelineViewMouseEvent *event)
}
time_movement = ValidateFrameMovement(time_movement, parent()->ghost_items_);
track_movement = ValidateTrackMovement(track_movement, parent()->ghost_items_);
rational earliest_ghost = RATIONAL_MAX;
@@ -163,11 +169,11 @@ void TimelineWidget::ImportTool::DragMove(TimelineViewMouseEvent *event)
foreach (TimelineViewGhostItem* ghost, parent()->ghost_items_) {
ghost->SetInAdjustment(time_movement);
ghost->SetOutAdjustment(time_movement);
ghost->SetTrackAdjustment(track_movement);
ghost->SetTrack(ghost_track);
ghost->SetY(ghost_y);
ghost->SetHeight(ghost_height);
TrackReference adjusted_track = ghost->GetAdjustedTrack();
ghost->SetY(parent()->GetTrackY(adjusted_track));
ghost->SetHeight(parent()->GetTrackHeight(adjusted_track));
earliest_ghost = qMin(earliest_ghost, ghost->GetAdjustedIn());
}
+2 -21
View File
@@ -274,7 +274,7 @@ void TimelineWidget::PointerTool::InitiateGhosts(TimelineViewBlockItem* clicked_
bool allow_gap_trimming)
{
// Convert selected items list to clips list
QList<TimelineViewBlockItem*> clips = GetSelectedClips();
QList<TimelineViewBlockItem*> clips = parent()->GetSelectedBlocks();
// If trimming multiple clips, we only trim the earliest in each track (trimming in) or the latest in each track
// (trimming out). If the current clip is NOT one of these, we only trim it.
@@ -351,7 +351,6 @@ TimelineViewGhostItem* TimelineWidget::PointerTool::AddGhostFromNull(const ratio
void TimelineWidget::PointerTool::AddGhostInternal(TimelineViewGhostItem* ghost, olive::timeline::MovementMode mode)
{
ghost->SetScale(parent()->scale_);
ghost->SetMode(mode);
// Prepare snap points (optimizes snapping for later)
@@ -370,25 +369,7 @@ void TimelineWidget::PointerTool::AddGhostInternal(TimelineViewGhostItem* ghost,
break;
}
parent()->ghost_items_.append(ghost);
parent()->scene_.addItem(ghost);
}
QList<TimelineViewBlockItem *> TimelineWidget::PointerTool::GetSelectedClips()
{
QList<QGraphicsItem*> selected_items = parent()->scene_.selectedItems();
// Convert selected items list to clips list
QList<TimelineViewBlockItem*> clips;
foreach (QGraphicsItem* item, selected_items) {
TimelineViewBlockItem* clip_cast = dynamic_cast<TimelineViewBlockItem*>(item);
if (clip_cast != nullptr) {
clips.append(clip_cast);
}
}
return clips;
parent()->AddGhost(ghost);
}
bool TimelineWidget::PointerTool::IsClipTrimmable(TimelineViewBlockItem* clip,
+6 -4
View File
@@ -85,8 +85,8 @@ rational TimelineWidget::RippleTool::FrameValidateInternal(rational time_movemen
}
void TimelineWidget::RippleTool::InitiateGhosts(TimelineViewBlockItem *clicked_item,
olive::timeline::MovementMode trim_mode,
bool allow_gap_trimming)
olive::timeline::MovementMode trim_mode,
bool allow_gap_trimming)
{
Q_UNUSED(allow_gap_trimming)
@@ -134,12 +134,14 @@ void TimelineWidget::RippleTool::InitiateGhosts(TimelineViewBlockItem *clicked_i
&& block_before_ripple->next()->type() != Block::kEnd) {
TimelineViewGhostItem* ghost;
TrackReference track_ref(track->track_type(), track->Index());
if (block_before_ripple->type() == Block::kGap) {
// If this Block is already a Gap, ghost it now
ghost = AddGhostFromBlock(block_before_ripple, track->Index(), trim_mode);
ghost = AddGhostFromBlock(block_before_ripple, track_ref, trim_mode);
} else {
// If there's no gap here, we'll need to create one
ghost = AddGhostFromNull(block_before_ripple->out(), block_before_ripple->out(), track->Index(), trim_mode);
ghost = AddGhostFromNull(block_before_ripple->out(), block_before_ripple->out(), track_ref, trim_mode);
ghost->setData(TimelineViewGhostItem::kReferenceBlock, Node::PtrToValue(block_before_ripple));
}
+84 -13
View File
@@ -29,10 +29,10 @@ TimelineWidget::TimelineWidget(QWidget *parent) :
layout->addWidget(view_splitter);
// Video view
views_.append(new TimelineView(Qt::AlignBottom));
views_.append(new TimelineView(kTrackTypeVideo, Qt::AlignBottom));
// Audio view
views_.append(new TimelineView(Qt::AlignTop));
views_.append(new TimelineView(kTrackTypeAudio, Qt::AlignTop));
// Create tools
tools_.resize(olive::tool::kCount);
@@ -67,13 +67,21 @@ TimelineWidget::TimelineWidget(QWidget *parent) :
connect(view->horizontalScrollBar(), SIGNAL(valueChanged(int)), ruler_, SLOT(SetScroll(int)));
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&)));
connect(view, SIGNAL(TimeChanged(const int64_t&)), ruler_, SLOT(SetTime(const int64_t&)));
connect(view, SIGNAL(TimeChanged(const int64_t&)), this, SIGNAL(TimeChanged(const int64_t&)));
connect(horizontal_scroll_, SIGNAL(valueChanged(int)), view->horizontalScrollBar(), SLOT(setValue(int)));
connect(view->horizontalScrollBar(), SIGNAL(valueChanged(int)), horizontal_scroll_, SLOT(setValue(int)));
connect(view, SIGNAL(MousePressed(TimelineViewMouseEvent*)), this, SLOT(ViewMousePressed(TimelineViewMouseEvent*)));
connect(view, SIGNAL(MouseMoved(TimelineViewMouseEvent*)), this, SLOT(ViewMouseMoved(TimelineViewMouseEvent*)));
connect(view, SIGNAL(MouseReleased(TimelineViewMouseEvent*)), this, SLOT(ViewMouseReleased(TimelineViewMouseEvent*)));
connect(view, SIGNAL(MouseDoubleClicked(TimelineViewMouseEvent*)), this, SLOT(ViewMouseDoubleClicked(TimelineViewMouseEvent*)));
connect(view, SIGNAL(DragEntered(TimelineViewMouseEvent*)), this, SLOT(ViewDragEntered(TimelineViewMouseEvent*)));
connect(view, SIGNAL(DragMoved(TimelineViewMouseEvent*)), this, SLOT(ViewDragMoved(TimelineViewMouseEvent*)));
connect(view, SIGNAL(DragLeft(QDragLeaveEvent*)), this, SLOT(ViewDragLeft(QDragLeaveEvent*)));
connect(view, SIGNAL(DragDropped(TimelineViewMouseEvent*)), this, SLOT(ViewDragDropped(TimelineViewMouseEvent*)));
// Connect each view's scroll to each other
foreach (TimelineView* other_view, views_) {
if (view != other_view) {
@@ -141,32 +149,46 @@ void TimelineWidget::ConnectTimelineNode(TimelineOutput *node)
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*)));
disconnect(timeline_node_, SIGNAL(TrackAdded(TrackOutput*)), this, SLOT(AddTrack(TrackOutput*)));
disconnect(timeline_node_, SIGNAL(TrackRemoved(TrackOutput*)), this, SLOT(RemoveTrack(TrackOutput*)));
disconnect(timeline_node_, SIGNAL(TimebaseChanged(const rational&)), this, SLOT(SetTimebase(const rational&)));
disconnect(timeline_node_, SIGNAL(TimelineCleared()), this, SLOT(Clear()));
SetTimebase(0);
Clear();
}
timeline_node_ = node;
for (int track_type=0;track_type<views_.size();track_type++) {
views_.at(track_type)->ConnectTimelineNode(node->track_list(static_cast<TrackType>(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*)));
connect(timeline_node_, SIGNAL(TrackAdded(TrackOutput*, TrackType)), this, SLOT(AddTrack(TrackOutput*, TrackType)));
connect(timeline_node_, SIGNAL(TrackRemoved(TrackOutput*)), this, SLOT(RemoveTrack(TrackOutput*)));
connect(timeline_node_, SIGNAL(TimebaseChanged(const rational&)), this, SLOT(SetTimebase(const rational&)));
SetTimebase(timeline_node_->Timebase());
for (int i=0;i<views_.size();i++) {
TrackType track_type = static_cast<TrackType>(i);
TimelineView* view = views_.at(i);
foreach (TimelineView* view, views_) {
view->SetEndTime(timeline_node_->timeline_length());
// Defer to the track to make all the block UI items necessary
foreach (TrackOutput* track, timeline_node_->track_list(track_type)->Tracks()) {
AddTrack(track, track_type);
}
}
}
}
void TimelineWidget::DisconnectTimelineNode()
{
timeline_node_ = nullptr;
foreach (TimelineView* view, views_) {
view->DisconnectTimelineNode();
}
ConnectTimelineNode(nullptr);
}
void TimelineWidget::ZoomIn()
@@ -276,6 +298,25 @@ void TimelineWidget::GoToNextCut()
}
}
QList<TimelineViewBlockItem *> TimelineWidget::GetSelectedBlocks()
{
QList<TimelineViewBlockItem *> list;
QMapIterator<Block*, TimelineViewBlockItem*> iterator(block_items_);
while (iterator.hasNext()) {
iterator.next();
TimelineViewBlockItem* item = iterator.value();
if (item != nullptr && item->isSelected()) {
list.append(item);
}
}
return list;
}
void TimelineWidget::RippleEditTo(olive::timeline::MovementMode mode, bool insert_gaps)
{
rational playhead_time = olive::timestamp_to_time(playhead_, timebase());
@@ -514,3 +555,33 @@ void TimelineWidget::RemoveBlock(Block *block)
block_items_.remove(block);
}
void TimelineWidget::AddTrack(TrackOutput *track, TrackType type)
{
foreach (Block* b, track->Blocks()) {
AddBlock(b, TrackReference(type, track->Index()));
}
}
void TimelineWidget::RemoveTrack(TrackOutput *track)
{
foreach (Block* b, track->Blocks()) {
RemoveBlock(b);
}
}
void TimelineWidget::BlockChanged()
{
TimelineViewRect* rect = block_items_[static_cast<Block*>(sender())];
if (rect != nullptr) {
rect->UpdateRect();
}
}
void TimelineWidget::AddGhost(TimelineViewGhostItem *ghost)
{
ghost->SetScale(scale_);
ghost_items_.append(ghost);
views_.at(ghost->Track().type())->scene()->addItem(ghost);
}
+15 -2
View File
@@ -47,6 +47,8 @@ public:
void GoToNextCut();
QList<TimelineViewBlockItem*> GetSelectedBlocks();
public slots:
void SetTimebase(const rational& timebase);
@@ -180,8 +182,6 @@ private:
void AddGhostInternal(TimelineViewGhostItem* ghost, olive::timeline::MovementMode mode);
QList<TimelineViewBlockItem*> GetSelectedClips();
bool IsClipTrimmable(TimelineViewBlockItem* clip,
const QList<TimelineViewBlockItem*>& items,
const olive::timeline::MovementMode& mode);
@@ -325,6 +325,8 @@ private:
void CenterOn(qreal scene_pos);
void AddGhost(TimelineViewGhostItem* ghost);
private slots:
void SetScale(double scale);
@@ -345,6 +347,17 @@ private slots:
void AddBlock(Block* block, TrackReference track);
void RemoveBlock(Block* block);
void AddTrack(TrackOutput* track, TrackType type);
void RemoveTrack(TrackOutput* track);
/**
* @brief Slot for when a Block node changes its parameters and the graphics need to update
*
* This slot does a static_cast on sender() to Block*, meaning all objects triggering this slot must be Blocks or
* derivatives.
*/
void BlockChanged();
};
#endif // TIMELINEWIDGET_H