timebasedwidget: rewrote scroll catchup code
Code is much better. Less hacky queuing, implements cooldowns to improve navigation, and introduces a framework so that subclasses can make use of catchup/cooldown code too with any scrollbar they want
This commit is contained in:
@@ -103,6 +103,7 @@ CurveWidget::CurveWidget(QWidget *parent) :
|
||||
connect(view_, &CurveView::SelectionChanged, this, &CurveWidget::SelectionChanged);
|
||||
connect(view_, &CurveView::ScaleChanged, this, &CurveWidget::SetScale);
|
||||
connect(view_, &CurveView::Dragged, this, &CurveWidget::KeyframeViewDragged);
|
||||
connect(view_, &CurveView::Released, this, &CurveWidget::KeyframeViewReleased);
|
||||
|
||||
// TimeBasedWidget's scrollbar has extra functionality that we can take advantage of
|
||||
view_->setHorizontalScrollBar(scrollbar());
|
||||
@@ -379,15 +380,14 @@ void CurveWidget::InputSelectionChanged(const NodeKeyframeTrackReference& ref)
|
||||
|
||||
void CurveWidget::KeyframeViewDragged(int x, int y)
|
||||
{
|
||||
QMetaObject::invokeMethod(this, "CatchUpScrollToPoint", Qt::QueuedConnection,
|
||||
Q_ARG(int, x));
|
||||
QMetaObject::invokeMethod(this, "CatchUpYScrollToPoint", Qt::QueuedConnection,
|
||||
Q_ARG(int, y));
|
||||
SetCatchUpScrollValue(x);
|
||||
SetCatchUpScrollValue(view_->verticalScrollBar(), y, view_->height());
|
||||
}
|
||||
|
||||
void CurveWidget::CatchUpYScrollToPoint(int point)
|
||||
void CurveWidget::KeyframeViewReleased()
|
||||
{
|
||||
PageScrollInternal(view_->verticalScrollBar(), view_->height(), point, false);
|
||||
StopCatchUpScrollTimer();
|
||||
StopCatchUpScrollTimer(view_->verticalScrollBar());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -122,8 +122,7 @@ private slots:
|
||||
void InputSelectionChanged(const NodeKeyframeTrackReference& ref);
|
||||
|
||||
void KeyframeViewDragged(int x, int y);
|
||||
|
||||
void CatchUpYScrollToPoint(int point);
|
||||
void KeyframeViewReleased();
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -290,8 +290,7 @@ void KeyframeView::mouseMoveEvent(QMouseEvent *event)
|
||||
|
||||
if (event->buttons()) {
|
||||
// Signal cursor pos in case we should scroll to catch up to it
|
||||
QPointF scene_pos = mapToScene(event->pos());
|
||||
emit Dragged(scene_pos.x(), scene_pos.y());
|
||||
emit Dragged(event->pos().x(), event->pos().y());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -309,6 +308,7 @@ void KeyframeView::mouseReleaseEvent(QMouseEvent *event)
|
||||
selection_manager_.DragStop(command);
|
||||
KeyframeDragRelease(event, command);
|
||||
Core::instance()->undo_stack()->push(command);
|
||||
emit Released();
|
||||
} else if (selection_manager_.IsRubberBanding()) {
|
||||
selection_manager_.RubberBandStop();
|
||||
Redraw();
|
||||
|
||||
@@ -88,6 +88,8 @@ signals:
|
||||
|
||||
void SelectionChanged();
|
||||
|
||||
void Released();
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QMouseEvent *event) override;
|
||||
virtual void mouseMoveEvent(QMouseEvent *event) override;
|
||||
|
||||
@@ -132,6 +132,7 @@ NodeParamView::NodeParamView(bool create_keyframe_view, QWidget *parent) :
|
||||
connect(keyframe_view_, &KeyframeView::TimeChanged, ruler(), &TimeRuler::SetTime);
|
||||
connect(keyframe_view_, &KeyframeView::TimeChanged, this, &NodeParamView::SetTime);
|
||||
connect(keyframe_view_, &KeyframeView::Dragged, this, &NodeParamView::KeyframeViewDragged);
|
||||
connect(keyframe_view_, &KeyframeView::Released, this, &NodeParamView::KeyframeViewReleased);
|
||||
|
||||
// Connect keyframe view scaling to this
|
||||
connect(keyframe_view_, &KeyframeView::ScaleChanged, this, &NodeParamView::SetScale);
|
||||
@@ -929,7 +930,12 @@ void NodeParamView::KeyframeViewDragged(int x, int y)
|
||||
{
|
||||
Q_UNUSED(y)
|
||||
|
||||
QMetaObject::invokeMethod(this, "CatchUpScrollToPoint", Qt::QueuedConnection, Q_ARG(int, x));
|
||||
SetCatchUpScrollValue(x);
|
||||
}
|
||||
|
||||
void NodeParamView::KeyframeViewReleased()
|
||||
{
|
||||
StopCatchUpScrollTimer();
|
||||
}
|
||||
|
||||
void NodeParamView::UpdateElementY()
|
||||
|
||||
@@ -165,6 +165,7 @@ private slots:
|
||||
//void FocusChanged(QWidget *old, QWidget *now);
|
||||
|
||||
void KeyframeViewDragged(int x, int y);
|
||||
void KeyframeViewReleased();
|
||||
|
||||
void NodeAddedToContext(Node *n);
|
||||
|
||||
|
||||
@@ -52,6 +52,10 @@ TimeBasedWidget::TimeBasedWidget(bool ruler_text_visible, bool ruler_cache_statu
|
||||
connect(scrollbar_, &ResizableScrollBar::ResizeMoved, this, &TimeBasedWidget::ScrollBarResizeMoved);
|
||||
|
||||
PassWheelEventsToScrollBar(ruler_);
|
||||
|
||||
catchup_scroll_timer_ = new QTimer(this);
|
||||
catchup_scroll_timer_->setInterval(250); // Hardcoded 1/4 scroll limit value
|
||||
connect(catchup_scroll_timer_, &QTimer::timeout, this, &TimeBasedWidget::CatchUpTimerTimeout);
|
||||
}
|
||||
|
||||
void TimeBasedWidget::SetScaleAndCenterOnPlayhead(const double &scale)
|
||||
@@ -217,6 +221,15 @@ void TimeBasedWidget::CatchUpScrollToPoint(int point)
|
||||
PageScrollInternal(point, false);
|
||||
}
|
||||
|
||||
void TimeBasedWidget::CatchUpTimerTimeout()
|
||||
{
|
||||
for (auto it=catchup_scroll_values_.cbegin(); it!=catchup_scroll_values_.cend(); it++) {
|
||||
QScrollBar *sb = it.key();
|
||||
const CatchUpScrollData &d = it.value();
|
||||
PageScrollInternal(sb, d.maximum, sb->value() + d.value, false);
|
||||
}
|
||||
}
|
||||
|
||||
void TimeBasedWidget::AutoUpdateTimebase()
|
||||
{
|
||||
rational video_tb = viewer_node_->GetVideoParams().frame_rate_as_time_base();
|
||||
@@ -301,6 +314,36 @@ void TimeBasedWidget::PassWheelEventsToScrollBar(QObject *object)
|
||||
object->installEventFilter(this);
|
||||
}
|
||||
|
||||
void TimeBasedWidget::SetCatchUpScrollValue(QScrollBar *b, int v, int maximum)
|
||||
{
|
||||
CatchUpScrollData &cudata = catchup_scroll_values_[b];
|
||||
cudata.value = v;
|
||||
cudata.maximum = maximum;
|
||||
|
||||
static const qint64 min_cooldown = 100; // Hardcoded 1/10 sec cooldown
|
||||
if (QDateTime::currentMSecsSinceEpoch() - cudata.last_forced >= min_cooldown) {
|
||||
QMetaObject::invokeMethod(this, &TimeBasedWidget::CatchUpTimerTimeout, Qt::QueuedConnection);
|
||||
cudata.last_forced = QDateTime::currentMSecsSinceEpoch();
|
||||
}
|
||||
|
||||
if (!catchup_scroll_timer_->isActive()) {
|
||||
catchup_scroll_timer_->start();
|
||||
}
|
||||
}
|
||||
|
||||
void TimeBasedWidget::SetCatchUpScrollValue(int v)
|
||||
{
|
||||
SetCatchUpScrollValue(scrollbar_, v, ruler()->width());
|
||||
}
|
||||
|
||||
void TimeBasedWidget::StopCatchUpScrollTimer(QScrollBar *b)
|
||||
{
|
||||
catchup_scroll_values_.remove(b);
|
||||
if (catchup_scroll_values_.empty()) {
|
||||
catchup_scroll_timer_->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void TimeBasedWidget::SetTime(const rational &time)
|
||||
{
|
||||
if (UserIsDraggingPlayhead()) {
|
||||
|
||||
@@ -150,6 +150,14 @@ protected:
|
||||
|
||||
void PassWheelEventsToScrollBar(QObject* object);
|
||||
|
||||
void SetCatchUpScrollValue(QScrollBar *b, int v, int maximum);
|
||||
void SetCatchUpScrollValue(int v);
|
||||
void StopCatchUpScrollTimer(QScrollBar *b);
|
||||
void StopCatchUpScrollTimer()
|
||||
{
|
||||
StopCatchUpScrollTimer(scrollbar_);
|
||||
}
|
||||
|
||||
virtual const QVector<Block*> *GetSnapBlocks() const { return nullptr; }
|
||||
virtual const QVector<KeyframeViewInputConnection*> *GetSnapKeyframes() const { return nullptr; }
|
||||
virtual const std::vector<NodeKeyframe*> *GetSnapIgnoreKeyframes() const { return nullptr; }
|
||||
@@ -228,6 +236,14 @@ private:
|
||||
TimelineWorkArea *workarea_;
|
||||
TimelineMarkerList *markers_;
|
||||
|
||||
QTimer *catchup_scroll_timer_;
|
||||
struct CatchUpScrollData {
|
||||
qint64 last_forced = 0;
|
||||
int maximum;
|
||||
int value;
|
||||
};
|
||||
QMap<QScrollBar*, CatchUpScrollData> catchup_scroll_values_;
|
||||
|
||||
private slots:
|
||||
void UpdateMaximumScroll();
|
||||
|
||||
@@ -247,6 +263,8 @@ private slots:
|
||||
|
||||
void CatchUpScrollToPoint(int point);
|
||||
|
||||
void CatchUpTimerTimeout();
|
||||
|
||||
void AutoUpdateTimebase();
|
||||
|
||||
void ConnectedNodeRemovedFromGraph();
|
||||
|
||||
@@ -906,8 +906,7 @@ void TimelineWidget::ViewMouseMoved(TimelineViewMouseEvent *event)
|
||||
|
||||
UpdateViewports();
|
||||
|
||||
QMetaObject::invokeMethod(this, "CatchUpScrollToPoint", Qt::QueuedConnection,
|
||||
Q_ARG(int, qRound(event->GetSceneX())));
|
||||
SetCatchUpScrollValue(event->GetScreenPos().x());
|
||||
} else {
|
||||
// Mouse is not down, attempt a hover event
|
||||
TimelineTool* hover_tool = GetActiveTool();
|
||||
@@ -922,6 +921,8 @@ void TimelineWidget::ViewMouseMoved(TimelineViewMouseEvent *event)
|
||||
|
||||
void TimelineWidget::ViewMouseReleased(TimelineViewMouseEvent *event)
|
||||
{
|
||||
StopCatchUpScrollTimer();
|
||||
|
||||
if (active_tool_) {
|
||||
if (GetConnectedNode()) {
|
||||
active_tool_->MouseRelease(event);
|
||||
@@ -956,16 +957,22 @@ void TimelineWidget::ViewDragMoved(TimelineViewMouseEvent *event)
|
||||
{
|
||||
import_tool_->DragMove(event);
|
||||
UpdateViewports();
|
||||
|
||||
SetCatchUpScrollValue(event->GetScreenPos().x());
|
||||
}
|
||||
|
||||
void TimelineWidget::ViewDragLeft(QDragLeaveEvent *event)
|
||||
{
|
||||
StopCatchUpScrollTimer();
|
||||
|
||||
import_tool_->DragLeave(event);
|
||||
UpdateViewports();
|
||||
}
|
||||
|
||||
void TimelineWidget::ViewDragDropped(TimelineViewMouseEvent *event)
|
||||
{
|
||||
StopCatchUpScrollTimer();
|
||||
|
||||
import_tool_->DragDrop(event);
|
||||
UpdateViewports();
|
||||
}
|
||||
|
||||
@@ -430,7 +430,8 @@ TimelineViewMouseEvent TimelineView::CreateMouseEvent(const QPoint& pos, Qt::Mou
|
||||
{
|
||||
QPointF scene_pt = mapToScene(pos);
|
||||
|
||||
return TimelineViewMouseEvent(scene_pt.x(),
|
||||
return TimelineViewMouseEvent(scene_pt,
|
||||
pos,
|
||||
GetScale(),
|
||||
timebase(),
|
||||
Track::Reference(ConnectedTrackType(), SceneToTrack(scene_pt.y())),
|
||||
|
||||
@@ -34,13 +34,15 @@ namespace olive {
|
||||
class TimelineViewMouseEvent
|
||||
{
|
||||
public:
|
||||
TimelineViewMouseEvent(const qreal& scene_x,
|
||||
TimelineViewMouseEvent(const QPointF& scene_pos,
|
||||
const QPoint &screen_pos,
|
||||
const double& scale_x,
|
||||
const rational& timebase,
|
||||
const Track::Reference &track,
|
||||
const Qt::MouseButton &button,
|
||||
const Qt::KeyboardModifiers& modifiers = Qt::NoModifier) :
|
||||
scene_x_(scene_x),
|
||||
scene_pos_(scene_pos),
|
||||
screen_pos_(screen_pos),
|
||||
scale_x_(scale_x),
|
||||
timebase_(timebase),
|
||||
track_(track),
|
||||
@@ -73,7 +75,7 @@ public:
|
||||
*/
|
||||
rational GetFrame(bool round = false) const
|
||||
{
|
||||
return TimeScaledObject::SceneToTime(scene_x_, scale_x_, timebase_, round);
|
||||
return TimeScaledObject::SceneToTime(GetSceneX(), scale_x_, timebase_, round);
|
||||
}
|
||||
|
||||
const Track::Reference& GetTrack() const
|
||||
@@ -96,11 +98,14 @@ public:
|
||||
source_event_ = event;
|
||||
}
|
||||
|
||||
const qreal& GetSceneX() const
|
||||
qreal GetSceneX() const
|
||||
{
|
||||
return scene_x_;
|
||||
return scene_pos_.x();
|
||||
}
|
||||
|
||||
const QPointF &GetScenePos() const { return scene_pos_; }
|
||||
const QPoint &GetScreenPos() const { return screen_pos_; }
|
||||
|
||||
const Qt::MouseButton& GetButton() const
|
||||
{
|
||||
return button_;
|
||||
@@ -122,7 +127,8 @@ public:
|
||||
void SetBypassImportBuffer(bool e) { bypass_import_buffer_ = e; }
|
||||
|
||||
private:
|
||||
qreal scene_x_;
|
||||
QPointF scene_pos_;
|
||||
QPoint screen_pos_;
|
||||
double scale_x_;
|
||||
rational timebase_;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user