timeline hierarchical length signalling

This commit is contained in:
itsmattkc
2019-10-07 02:33:52 +11:00
parent f34eb0dfb6
commit 31f11cd87d
17 changed files with 215 additions and 188 deletions
+2 -2
View File
@@ -21,6 +21,8 @@ set(OLIVE_SOURCES
${OLIVE_SOURCES}
widget/timelineview/timelineplayhead.h
widget/timelineview/timelineplayhead.cpp
widget/timelineview/timelinescaledobject.h
widget/timelineview/timelinescaledobject.cpp
widget/timelineview/timelineview.h
widget/timelineview/timelineview.cpp
widget/timelineview/timelineviewrect.h
@@ -31,7 +33,5 @@ set(OLIVE_SOURCES
widget/timelineview/timelineviewenditem.cpp
widget/timelineview/timelineviewghostitem.h
widget/timelineview/timelineviewghostitem.cpp
widget/timelineview/timelineviewplayheaditem.h
widget/timelineview/timelineviewplayheaditem.cpp
PARENT_SCOPE
)
@@ -0,0 +1,12 @@
#include "timelinescaledobject.h"
TimelineScaledObject::TimelineScaledObject() :
scale_(1.0)
{
}
double TimelineScaledObject::TimeToScreenCoord(const rational &time)
{
return time.toDouble() * scale_;
}
@@ -0,0 +1,20 @@
#ifndef TIMELINESCALEDOBJECT_H
#define TIMELINESCALEDOBJECT_H
#include "common/rational.h"
class TimelineScaledObject
{
public:
TimelineScaledObject();
protected:
double TimeToScreenCoord(const rational& time);
double scale_;
private:
};
#endif // TIMELINESCALEDOBJECT_H
+50 -16
View File
@@ -45,7 +45,8 @@ TimelineView::TimelineView(Qt::Alignment vertical_alignment, QWidget *parent) :
hand_tool_(this),
zoom_tool_(this),
timeline_node_(nullptr),
playhead_(0)
playhead_(0),
use_tracklist_length_directly_(true)
{
Q_ASSERT(vertical_alignment == Qt::AlignTop || vertical_alignment == Qt::AlignBottom);
setAlignment(Qt::AlignLeft | vertical_alignment);
@@ -57,10 +58,6 @@ TimelineView::TimelineView(Qt::Alignment vertical_alignment, QWidget *parent) :
connect(&scene_, SIGNAL(changed(const QList<QRectF>&)), this, SLOT(UpdateSceneRect()));
// Create playhead line
playhead_line_ = new TimelineViewPlayheadItem();
scene_.addItem(playhead_line_);
// Create end item
end_item_ = new TimelineViewEndItem();
scene_.addItem(end_item_);
@@ -138,7 +135,9 @@ void TimelineView::SetScale(const double &scale)
ghost->SetScale(scale_);
}
playhead_line_->SetScale(scale_);
// Force redraw for playhead
viewport()->update();
end_item_->SetScale(scale_);
}
@@ -146,8 +145,6 @@ void TimelineView::SetTimebase(const rational &timebase)
{
timebase_ = timebase;
timebase_dbl_ = timebase_.toDouble();
playhead_line_->SetTimebase(timebase_);
}
void TimelineView::Clear()
@@ -175,6 +172,7 @@ void TimelineView::ConnectTimelineNode(TrackList *node)
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&)));
Clear();
}
@@ -192,6 +190,7 @@ void TimelineView::ConnectTimelineNode(TrackList *node)
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&)));
foreach (TrackOutput* track, timeline_node_->Tracks()) {
// Defer to the track to make all the block UI items necessary
@@ -223,11 +222,17 @@ void TimelineView::DeselectAll()
}
}
void TimelineView::SetUseTrackListLengthDirectly(bool use)
{
use_tracklist_length_directly_ = use;
}
void TimelineView::SetTime(const int64_t time)
{
playhead_ = time;
playhead_line_->SetPlayhead(playhead_);
// Force redraw for playhead
viewport()->update();
}
void TimelineView::mousePressEvent(QMouseEvent *event)
@@ -288,6 +293,24 @@ void TimelineView::resizeEvent(QResizeEvent *event)
UpdateSceneRect();
}
void TimelineView::drawForeground(QPainter *painter, const QRectF &rect)
{
QGraphicsView::drawForeground(painter, rect);
double x = TimeToScreenCoord(rational(playhead_ * timebase_.numerator(), timebase_.denominator()));
double width = TimeToScreenCoord(timebase_);
QRectF playhead_rect(x, rect.top(), width, rect.height());
painter->setPen(Qt::NoPen);
painter->setBrush(playhead_style_.PlayheadHighlightColor());
painter->drawRect(playhead_rect);
painter->setPen(playhead_style_.PlayheadColor());
painter->setBrush(Qt::NoBrush);
painter->drawLine(QLineF(playhead_rect.topLeft(), playhead_rect.bottomLeft()));
}
TimelineView::Tool *TimelineView::GetActiveTool()
{
switch (olive::core.tool()) {
@@ -400,6 +423,11 @@ void TimelineView::UserSetTime(const int64_t &time)
emit TimeChanged(time);
}
rational TimelineView::GetPlayheadTime()
{
return rational(playhead_ * timebase_.numerator(), timebase_.denominator());
}
void TimelineView::BlockChanged()
{
TimelineViewRect* rect = block_items_[static_cast<Block*>(sender())];
@@ -434,13 +462,7 @@ void TimelineView::UpdateSceneRect()
}
// Ensure the scene is always the full length of the timeline with a gap at the end to work with
if (timeline_node_ != nullptr) {
end_item_->SetEndTime(timeline_node_->TimelineLength());
end_item_->SetEndPadding(width()/4);
}
// Ensure playhead is the correct height
playhead_line_->SetHeight(viewport()->height()-1);
end_item_->SetEndPadding(width()/4);
// If the scene is already this rect, do nothing
if (scene_.sceneRect() == bounding_rect) {
@@ -449,3 +471,15 @@ 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);
}
+24 -6
View File
@@ -29,10 +29,10 @@
#include "node/block/clip/clip.h"
#include "node/output/timeline/timeline.h"
#include "timelineplayhead.h"
#include "timelineviewblockitem.h"
#include "timelineviewenditem.h"
#include "timelineviewghostitem.h"
#include "timelineviewplayheaditem.h"
#include "widget/timelineview/undo/undo.h"
#include "undo/undostack.h"
@@ -41,7 +41,7 @@
*
* This widget primarily exposes users to viewing and modifying Block nodes, usually through a TimelineOutput node.
*/
class TimelineView : public QGraphicsView
class TimelineView : public QGraphicsView, public TimelineScaledObject
{
Q_OBJECT
public:
@@ -57,6 +57,10 @@ public:
void DeselectAll();
void SetUseTrackListLengthDirectly(bool use);
void SetEndTime(const rational& length);
public slots:
void SetTimebase(const rational& timebase);
@@ -91,6 +95,8 @@ protected:
virtual void resizeEvent(QResizeEvent *event) override;
virtual void drawForeground(QPainter *painter, const QRectF &rect) override;
private:
class Tool
@@ -353,8 +359,6 @@ private:
QGraphicsScene scene_;
double scale_;
rational timebase_;
double timebase_dbl_;
@@ -367,12 +371,20 @@ private:
QVector<int> track_heights_;
TimelineViewPlayheadItem* playhead_line_;
TimelineViewEndItem* end_item_;
Tool* active_tool_;
TimelinePlayhead playhead_style_;
rational GetPlayheadTime();
void UpdatePlayheadRect();
QRect playhead_rect_;
bool use_tracklist_length_directly_;
private slots:
/**
* @brief Slot for when a Block node changes its parameters and the graphics need to update
@@ -386,6 +398,12 @@ private slots:
* @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
@@ -1,72 +0,0 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#include "timelineviewplayheaditem.h"
#include <QDebug>
#include <QGraphicsScene>
#include <QPainter>
#include <QtMath>
TimelineViewPlayheadItem::TimelineViewPlayheadItem(QGraphicsItem *parent) :
TimelineViewRect(parent),
playhead_(0)
{
// Ensure this item is always on top
setZValue(100);
}
void TimelineViewPlayheadItem::SetPlayhead(const int64_t &playhead)
{
playhead_ = playhead;
UpdateRect();
}
void TimelineViewPlayheadItem::SetTimebase(const rational &timebase)
{
timebase_ = timebase;
UpdateRect();
}
void TimelineViewPlayheadItem::UpdateRect()
{
double x = TimeToScreenCoord(rational(playhead_ * timebase_.numerator(), timebase_.denominator()));
double width = TimeToScreenCoord(timebase_);
setRect(0, 0, width, height_);
setPos(x, y_);
}
void TimelineViewPlayheadItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
Q_UNUSED(option)
Q_UNUSED(widget)
// FIXME: Make adjustable through CSS
painter->setPen(Qt::NoPen);
painter->setBrush(style_.PlayheadHighlightColor());
painter->drawRect(rect());
painter->setPen(style_.PlayheadColor());
painter->setBrush(Qt::NoBrush);
painter->drawLine(QLineF(rect().topLeft(), rect().bottomLeft()));
}
@@ -1,52 +0,0 @@
/***
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 <http://www.gnu.org/licenses/>.
***/
#ifndef TIMELINEVIEWPLAYHEADITEM_H
#define TIMELINEVIEWPLAYHEADITEM_H
#include "timelineplayhead.h"
#include "timelineviewrect.h"
/**
* @brief A graphical representation of the playhead on the Timeline
*/
class TimelineViewPlayheadItem : public TimelineViewRect
{
public:
TimelineViewPlayheadItem(QGraphicsItem* parent = nullptr);
void SetPlayhead(const int64_t& playhead);
void SetTimebase(const rational& timebase);
virtual void UpdateRect() override;
protected:
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = nullptr) override;
private:
int64_t playhead_;
rational timebase_;
TimelinePlayhead style_;
};
#endif // TIMELINEVIEWPLAYHEADITEM_H
@@ -22,7 +22,6 @@
TimelineViewRect::TimelineViewRect(QGraphicsItem* parent) :
QGraphicsRectItem(parent),
scale_(1.0),
y_(0),
height_(0)
{
@@ -69,8 +68,3 @@ void TimelineViewRect::SetScale(const double &scale)
UpdateRect();
}
double TimelineViewRect::TimeToScreenCoord(const rational &time)
{
return time.toDouble() * scale_;
}
+2 -6
View File
@@ -23,12 +23,12 @@
#include <QGraphicsRectItem>
#include "common/rational.h"
#include "timelinescaledobject.h"
/**
* @brief A base class for graphical representations of Block nodes
*/
class TimelineViewRect : public QGraphicsRectItem
class TimelineViewRect : public QGraphicsRectItem, public TimelineScaledObject
{
public:
TimelineViewRect(QGraphicsItem* parent = nullptr);
@@ -47,10 +47,6 @@ public:
virtual void UpdateRect() = 0;
protected:
double TimeToScreenCoord(const rational& time);
double scale_;
int y_;
int height_;
+3 -1
View File
@@ -141,11 +141,13 @@ bool TimelineView::Tool::SnapPoint(QList<rational> start_times, rational* moveme
}
if (snap_points & kSnapToPlayhead) {
qreal playhead_pos = parent()->playhead_line_->x();
rational playhead_abs_time = rational(parent()->playhead_ * parent()->timebase_.numerator(),
parent()->timebase_.denominator());
qreal playhead_pos = playhead_abs_time.toDouble() * parent()->scale_;
AttemptSnap(proposed_pts, playhead_pos, start_times, playhead_abs_time, movement, &diff);
}
+11
View File
@@ -39,6 +39,11 @@ void TimelineView::ZoomTool::MouseRelease(QMouseEvent *event)
{
double scale = parent()->scale_;
QPointF center_location = parent()->mapToScene(event->pos());
// Normalize zoom location for 1.0 scale
double scaled_x = center_location.x() / scale;
if (event->modifiers() & Qt::AltModifier) {
// Zoom out if the user clicks while holding Alt
scale *= 0.5;
@@ -49,4 +54,10 @@ void TimelineView::ZoomTool::MouseRelease(QMouseEvent *event)
parent()->SetScale(scale);
emit parent()->ScaleChanged(scale);
// Adjust zoom location for new scale
scaled_x *= scale;
center_location.setX(scaled_x);
parent()->centerOn(center_location);
}
@@ -61,6 +61,9 @@ TimelineWidget::TimelineWidget(QWidget *parent) :
}
}
// Split viewer 50/50
view_splitter->setSizes({INT_MAX, INT_MAX});
// FIXME: Magic number
SetScale(90.0);
}
@@ -105,6 +108,10 @@ void TimelineWidget::SetTime(const int64_t &timestamp)
void TimelineWidget::ConnectTimelineNode(TimelineOutput *node)
{
if (timeline_node_ != nullptr) {
disconnect(timeline_node_, SIGNAL(LengthChanged(const rational&)), this, SLOT(UpdateTimelineLength(const rational&)));
}
timeline_node_ = node;
int track_type = 0;
@@ -114,6 +121,14 @@ void TimelineWidget::ConnectTimelineNode(TimelineOutput *node)
track_type++;
}
if (timeline_node_ != nullptr) {
connect(timeline_node_, SIGNAL(LengthChanged(const rational&)), this, SLOT(UpdateTimelineLength(const rational&)));
foreach (TimelineView* view, views_) {
view->SetEndTime(timeline_node_->timeline_length());
}
}
}
void TimelineWidget::DisconnectTimelineNode()
@@ -313,3 +328,10 @@ void TimelineWidget::UpdateInternalTime(const int64_t &timestamp)
{
playhead_ = timestamp;
}
void TimelineWidget::UpdateTimelineLength(const rational &length)
{
foreach (TimelineView* view, views_) {
view->SetEndTime(length);
}
}
@@ -79,6 +79,8 @@ private slots:
void UpdateInternalTime(const int64_t& timestamp);
void UpdateTimelineLength(const rational& length);
};
#endif // TIMELINEWIDGET_H