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::SelectionChanged, this, &CurveWidget::SelectionChanged);
|
||||||
connect(view_, &CurveView::ScaleChanged, this, &CurveWidget::SetScale);
|
connect(view_, &CurveView::ScaleChanged, this, &CurveWidget::SetScale);
|
||||||
connect(view_, &CurveView::Dragged, this, &CurveWidget::KeyframeViewDragged);
|
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
|
// TimeBasedWidget's scrollbar has extra functionality that we can take advantage of
|
||||||
view_->setHorizontalScrollBar(scrollbar());
|
view_->setHorizontalScrollBar(scrollbar());
|
||||||
@@ -379,15 +380,14 @@ void CurveWidget::InputSelectionChanged(const NodeKeyframeTrackReference& ref)
|
|||||||
|
|
||||||
void CurveWidget::KeyframeViewDragged(int x, int y)
|
void CurveWidget::KeyframeViewDragged(int x, int y)
|
||||||
{
|
{
|
||||||
QMetaObject::invokeMethod(this, "CatchUpScrollToPoint", Qt::QueuedConnection,
|
SetCatchUpScrollValue(x);
|
||||||
Q_ARG(int, x));
|
SetCatchUpScrollValue(view_->verticalScrollBar(), y, view_->height());
|
||||||
QMetaObject::invokeMethod(this, "CatchUpYScrollToPoint", Qt::QueuedConnection,
|
|
||||||
Q_ARG(int, y));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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 InputSelectionChanged(const NodeKeyframeTrackReference& ref);
|
||||||
|
|
||||||
void KeyframeViewDragged(int x, int y);
|
void KeyframeViewDragged(int x, int y);
|
||||||
|
void KeyframeViewReleased();
|
||||||
void CatchUpYScrollToPoint(int point);
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -290,8 +290,7 @@ void KeyframeView::mouseMoveEvent(QMouseEvent *event)
|
|||||||
|
|
||||||
if (event->buttons()) {
|
if (event->buttons()) {
|
||||||
// Signal cursor pos in case we should scroll to catch up to it
|
// Signal cursor pos in case we should scroll to catch up to it
|
||||||
QPointF scene_pos = mapToScene(event->pos());
|
emit Dragged(event->pos().x(), event->pos().y());
|
||||||
emit Dragged(scene_pos.x(), scene_pos.y());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,6 +308,7 @@ void KeyframeView::mouseReleaseEvent(QMouseEvent *event)
|
|||||||
selection_manager_.DragStop(command);
|
selection_manager_.DragStop(command);
|
||||||
KeyframeDragRelease(event, command);
|
KeyframeDragRelease(event, command);
|
||||||
Core::instance()->undo_stack()->push(command);
|
Core::instance()->undo_stack()->push(command);
|
||||||
|
emit Released();
|
||||||
} else if (selection_manager_.IsRubberBanding()) {
|
} else if (selection_manager_.IsRubberBanding()) {
|
||||||
selection_manager_.RubberBandStop();
|
selection_manager_.RubberBandStop();
|
||||||
Redraw();
|
Redraw();
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ signals:
|
|||||||
|
|
||||||
void SelectionChanged();
|
void SelectionChanged();
|
||||||
|
|
||||||
|
void Released();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void mousePressEvent(QMouseEvent *event) override;
|
virtual void mousePressEvent(QMouseEvent *event) override;
|
||||||
virtual void mouseMoveEvent(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, ruler(), &TimeRuler::SetTime);
|
||||||
connect(keyframe_view_, &KeyframeView::TimeChanged, this, &NodeParamView::SetTime);
|
connect(keyframe_view_, &KeyframeView::TimeChanged, this, &NodeParamView::SetTime);
|
||||||
connect(keyframe_view_, &KeyframeView::Dragged, this, &NodeParamView::KeyframeViewDragged);
|
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 scaling to this
|
||||||
connect(keyframe_view_, &KeyframeView::ScaleChanged, this, &NodeParamView::SetScale);
|
connect(keyframe_view_, &KeyframeView::ScaleChanged, this, &NodeParamView::SetScale);
|
||||||
@@ -929,7 +930,12 @@ void NodeParamView::KeyframeViewDragged(int x, int y)
|
|||||||
{
|
{
|
||||||
Q_UNUSED(y)
|
Q_UNUSED(y)
|
||||||
|
|
||||||
QMetaObject::invokeMethod(this, "CatchUpScrollToPoint", Qt::QueuedConnection, Q_ARG(int, x));
|
SetCatchUpScrollValue(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeParamView::KeyframeViewReleased()
|
||||||
|
{
|
||||||
|
StopCatchUpScrollTimer();
|
||||||
}
|
}
|
||||||
|
|
||||||
void NodeParamView::UpdateElementY()
|
void NodeParamView::UpdateElementY()
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ private slots:
|
|||||||
//void FocusChanged(QWidget *old, QWidget *now);
|
//void FocusChanged(QWidget *old, QWidget *now);
|
||||||
|
|
||||||
void KeyframeViewDragged(int x, int y);
|
void KeyframeViewDragged(int x, int y);
|
||||||
|
void KeyframeViewReleased();
|
||||||
|
|
||||||
void NodeAddedToContext(Node *n);
|
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);
|
connect(scrollbar_, &ResizableScrollBar::ResizeMoved, this, &TimeBasedWidget::ScrollBarResizeMoved);
|
||||||
|
|
||||||
PassWheelEventsToScrollBar(ruler_);
|
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)
|
void TimeBasedWidget::SetScaleAndCenterOnPlayhead(const double &scale)
|
||||||
@@ -217,6 +221,15 @@ void TimeBasedWidget::CatchUpScrollToPoint(int point)
|
|||||||
PageScrollInternal(point, false);
|
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()
|
void TimeBasedWidget::AutoUpdateTimebase()
|
||||||
{
|
{
|
||||||
rational video_tb = viewer_node_->GetVideoParams().frame_rate_as_time_base();
|
rational video_tb = viewer_node_->GetVideoParams().frame_rate_as_time_base();
|
||||||
@@ -301,6 +314,36 @@ void TimeBasedWidget::PassWheelEventsToScrollBar(QObject *object)
|
|||||||
object->installEventFilter(this);
|
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)
|
void TimeBasedWidget::SetTime(const rational &time)
|
||||||
{
|
{
|
||||||
if (UserIsDraggingPlayhead()) {
|
if (UserIsDraggingPlayhead()) {
|
||||||
|
|||||||
@@ -150,6 +150,14 @@ protected:
|
|||||||
|
|
||||||
void PassWheelEventsToScrollBar(QObject* object);
|
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<Block*> *GetSnapBlocks() const { return nullptr; }
|
||||||
virtual const QVector<KeyframeViewInputConnection*> *GetSnapKeyframes() const { return nullptr; }
|
virtual const QVector<KeyframeViewInputConnection*> *GetSnapKeyframes() const { return nullptr; }
|
||||||
virtual const std::vector<NodeKeyframe*> *GetSnapIgnoreKeyframes() const { return nullptr; }
|
virtual const std::vector<NodeKeyframe*> *GetSnapIgnoreKeyframes() const { return nullptr; }
|
||||||
@@ -228,6 +236,14 @@ private:
|
|||||||
TimelineWorkArea *workarea_;
|
TimelineWorkArea *workarea_;
|
||||||
TimelineMarkerList *markers_;
|
TimelineMarkerList *markers_;
|
||||||
|
|
||||||
|
QTimer *catchup_scroll_timer_;
|
||||||
|
struct CatchUpScrollData {
|
||||||
|
qint64 last_forced = 0;
|
||||||
|
int maximum;
|
||||||
|
int value;
|
||||||
|
};
|
||||||
|
QMap<QScrollBar*, CatchUpScrollData> catchup_scroll_values_;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void UpdateMaximumScroll();
|
void UpdateMaximumScroll();
|
||||||
|
|
||||||
@@ -247,6 +263,8 @@ private slots:
|
|||||||
|
|
||||||
void CatchUpScrollToPoint(int point);
|
void CatchUpScrollToPoint(int point);
|
||||||
|
|
||||||
|
void CatchUpTimerTimeout();
|
||||||
|
|
||||||
void AutoUpdateTimebase();
|
void AutoUpdateTimebase();
|
||||||
|
|
||||||
void ConnectedNodeRemovedFromGraph();
|
void ConnectedNodeRemovedFromGraph();
|
||||||
|
|||||||
@@ -906,8 +906,7 @@ void TimelineWidget::ViewMouseMoved(TimelineViewMouseEvent *event)
|
|||||||
|
|
||||||
UpdateViewports();
|
UpdateViewports();
|
||||||
|
|
||||||
QMetaObject::invokeMethod(this, "CatchUpScrollToPoint", Qt::QueuedConnection,
|
SetCatchUpScrollValue(event->GetScreenPos().x());
|
||||||
Q_ARG(int, qRound(event->GetSceneX())));
|
|
||||||
} else {
|
} else {
|
||||||
// Mouse is not down, attempt a hover event
|
// Mouse is not down, attempt a hover event
|
||||||
TimelineTool* hover_tool = GetActiveTool();
|
TimelineTool* hover_tool = GetActiveTool();
|
||||||
@@ -922,6 +921,8 @@ void TimelineWidget::ViewMouseMoved(TimelineViewMouseEvent *event)
|
|||||||
|
|
||||||
void TimelineWidget::ViewMouseReleased(TimelineViewMouseEvent *event)
|
void TimelineWidget::ViewMouseReleased(TimelineViewMouseEvent *event)
|
||||||
{
|
{
|
||||||
|
StopCatchUpScrollTimer();
|
||||||
|
|
||||||
if (active_tool_) {
|
if (active_tool_) {
|
||||||
if (GetConnectedNode()) {
|
if (GetConnectedNode()) {
|
||||||
active_tool_->MouseRelease(event);
|
active_tool_->MouseRelease(event);
|
||||||
@@ -956,16 +957,22 @@ void TimelineWidget::ViewDragMoved(TimelineViewMouseEvent *event)
|
|||||||
{
|
{
|
||||||
import_tool_->DragMove(event);
|
import_tool_->DragMove(event);
|
||||||
UpdateViewports();
|
UpdateViewports();
|
||||||
|
|
||||||
|
SetCatchUpScrollValue(event->GetScreenPos().x());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimelineWidget::ViewDragLeft(QDragLeaveEvent *event)
|
void TimelineWidget::ViewDragLeft(QDragLeaveEvent *event)
|
||||||
{
|
{
|
||||||
|
StopCatchUpScrollTimer();
|
||||||
|
|
||||||
import_tool_->DragLeave(event);
|
import_tool_->DragLeave(event);
|
||||||
UpdateViewports();
|
UpdateViewports();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TimelineWidget::ViewDragDropped(TimelineViewMouseEvent *event)
|
void TimelineWidget::ViewDragDropped(TimelineViewMouseEvent *event)
|
||||||
{
|
{
|
||||||
|
StopCatchUpScrollTimer();
|
||||||
|
|
||||||
import_tool_->DragDrop(event);
|
import_tool_->DragDrop(event);
|
||||||
UpdateViewports();
|
UpdateViewports();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -430,7 +430,8 @@ TimelineViewMouseEvent TimelineView::CreateMouseEvent(const QPoint& pos, Qt::Mou
|
|||||||
{
|
{
|
||||||
QPointF scene_pt = mapToScene(pos);
|
QPointF scene_pt = mapToScene(pos);
|
||||||
|
|
||||||
return TimelineViewMouseEvent(scene_pt.x(),
|
return TimelineViewMouseEvent(scene_pt,
|
||||||
|
pos,
|
||||||
GetScale(),
|
GetScale(),
|
||||||
timebase(),
|
timebase(),
|
||||||
Track::Reference(ConnectedTrackType(), SceneToTrack(scene_pt.y())),
|
Track::Reference(ConnectedTrackType(), SceneToTrack(scene_pt.y())),
|
||||||
|
|||||||
@@ -34,13 +34,15 @@ namespace olive {
|
|||||||
class TimelineViewMouseEvent
|
class TimelineViewMouseEvent
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
TimelineViewMouseEvent(const qreal& scene_x,
|
TimelineViewMouseEvent(const QPointF& scene_pos,
|
||||||
|
const QPoint &screen_pos,
|
||||||
const double& scale_x,
|
const double& scale_x,
|
||||||
const rational& timebase,
|
const rational& timebase,
|
||||||
const Track::Reference &track,
|
const Track::Reference &track,
|
||||||
const Qt::MouseButton &button,
|
const Qt::MouseButton &button,
|
||||||
const Qt::KeyboardModifiers& modifiers = Qt::NoModifier) :
|
const Qt::KeyboardModifiers& modifiers = Qt::NoModifier) :
|
||||||
scene_x_(scene_x),
|
scene_pos_(scene_pos),
|
||||||
|
screen_pos_(screen_pos),
|
||||||
scale_x_(scale_x),
|
scale_x_(scale_x),
|
||||||
timebase_(timebase),
|
timebase_(timebase),
|
||||||
track_(track),
|
track_(track),
|
||||||
@@ -73,7 +75,7 @@ public:
|
|||||||
*/
|
*/
|
||||||
rational GetFrame(bool round = false) const
|
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
|
const Track::Reference& GetTrack() const
|
||||||
@@ -96,11 +98,14 @@ public:
|
|||||||
source_event_ = event;
|
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
|
const Qt::MouseButton& GetButton() const
|
||||||
{
|
{
|
||||||
return button_;
|
return button_;
|
||||||
@@ -122,7 +127,8 @@ public:
|
|||||||
void SetBypassImportBuffer(bool e) { bypass_import_buffer_ = e; }
|
void SetBypassImportBuffer(bool e) { bypass_import_buffer_ = e; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
qreal scene_x_;
|
QPointF scene_pos_;
|
||||||
|
QPoint screen_pos_;
|
||||||
double scale_x_;
|
double scale_x_;
|
||||||
rational timebase_;
|
rational timebase_;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user