Skip to content

Commit

Permalink
timeline: vastly improve behavior when scrolling and zooming
Browse files Browse the repository at this point in the history
  • Loading branch information
itsmattkc committed Mar 1, 2023
1 parent 9ff6e68 commit d0f16ef
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 52 deletions.
6 changes: 5 additions & 1 deletion app/widget/timebased/timebasedwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,6 @@ public slots:
void ConnectTimelineView(TimeBasedView* base);

void SetCatchUpScrollValue(QScrollBar *b, int v, int maximum);
void SetCatchUpScrollValue(int v);
void StopCatchUpScrollTimer(QScrollBar *b);

virtual const QVector<Block*> *GetSnapBlocks() const { return nullptr; }
Expand Down Expand Up @@ -169,11 +168,16 @@ protected slots:
StopCatchUpScrollTimer(scrollbar_);
}

void SetCatchUpScrollValue(int v);

signals:
void TimebaseChanged(const rational&);

void ConnectedNodeChanged(ViewerOutput* old, ViewerOutput* now);

protected slots:
virtual void SendCatchUpScrollEvent();

private:
/**
* @brief Set either in or out point to the current playhead
Expand Down
91 changes: 44 additions & 47 deletions app/widget/timelinewidget/timelinewidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,10 @@ void TimelineWidget::ScaleChangedEvent(const double &scale)
foreach (TimelineAndTrackView* view, views_) {
view->view()->SetScale(scale);
}

if (rubberband_.isVisible()) {
QMetaObject::invokeMethod(this, &TimelineWidget::ForceUpdateRubberBand, Qt::QueuedConnection);
}
}

void TimelineWidget::ConnectNodeEvent(ViewerOutput *n)
Expand Down Expand Up @@ -339,6 +343,15 @@ void TimelineWidget::DisconnectNodeEvent(ViewerOutput *n)
}
}

void TimelineWidget::SendCatchUpScrollEvent()
{
super::SendCatchUpScrollEvent();

if (rubberband_.isVisible()) {
this->ForceUpdateRubberBand();
}
}

void TimelineWidget::SelectAll()
{
QVector<Block*> newly_selected_blocks;
Expand Down Expand Up @@ -1564,6 +1577,13 @@ void TimelineWidget::MulticamEnabledTriggered(bool e)
Core::instance()->undo_stack()->pushIfHasChildren(command);
}

void TimelineWidget::ForceUpdateRubberBand()
{
if (rubberband_.isVisible()) {
this->MoveRubberBandSelect(rubberband_enable_selecting_, rubberband_select_links_);
}
}

void TimelineWidget::AddGhost(TimelineViewGhostItem *ghost)
{
ghost_items_.append(ghost);
Expand Down Expand Up @@ -1912,46 +1932,6 @@ void TimelineWidget::UpdateViewports(const Track::Type &type)
}
}

QVector<Block *> TimelineWidget::GetBlocksInGlobalRect(const QPoint &p1, const QPoint& p2)
{
QVector<Block*> blocks_in_rect;

// Determine which tracks are in the rect
for (int i=0; i<views_.size(); i++) {
TimelineView* view = views_.at(i)->view();

// Map global mouse coordinates to viewport
QRectF mapped_rect(view->mapToScene(view->viewport()->mapFromGlobal(p1)),
view->mapToScene(view->viewport()->mapFromGlobal(p2)));

// Normalize
mapped_rect = mapped_rect.normalized();

// Get tracks
TrackList* track_list = sequence()->track_list(static_cast<Track::Type>(i));

for (int j=0; j<track_list->GetTrackCount(); j++) {
int track_top = view->GetTrackY(j);
int track_bottom = track_top + view->GetTrackHeight(j);

if (!(track_bottom < mapped_rect.top() || track_top > mapped_rect.bottom())) {
// This track is in the rect, so we'll iterate through its blocks and see where they start
rational left_time = SceneToTime(mapped_rect.left());
rational right_time = SceneToTime(mapped_rect.right(), true);

Track* track = track_list->GetTrackAt(j);
foreach (Block* b, track->Blocks()) {
if (!(b->out() < left_time || b->in() > right_time)) {
blocks_in_rect.append(b);
}
}
}
}
}

return blocks_in_rect;
}

bool TimelineWidget::PasteInternal(bool insert)
{
if (!GetConnectedNode()) {
Expand Down Expand Up @@ -2039,11 +2019,12 @@ void TimelineWidget::RestoreSplitterState(const QByteArray &state)

void TimelineWidget::StartRubberBandSelect(const QPoint &global_cursor_start)
{
drag_origin_ = global_cursor_start;

// Start rubberband at origin
QPoint local_origin = mapFromGlobal(drag_origin_);
rubberband_.setGeometry(QRect(local_origin.x(), local_origin.y(), 0, 0));
// Store scene positions for each view
rubberband_scene_pos_.resize(views_.size());
for (int i = 0; i < rubberband_scene_pos_.size(); i++) {
TimelineView *v = views_.at(i)->view();
rubberband_scene_pos_[i] = v->UnscalePoint(v->mapToScene(v->mapFromGlobal(global_cursor_start)));
}

rubberband_.show();

Expand All @@ -2056,14 +2037,30 @@ void TimelineWidget::MoveRubberBandSelect(bool enable_selecting, bool select_lin
{
QPoint rubberband_now = QCursor::pos();

rubberband_.setGeometry(QRect(mapFromGlobal(drag_origin_), mapFromGlobal(rubberband_now)).normalized());
TimelineView *fv = views_.first()->view();
const QPointF &rubberband_scene_start = rubberband_scene_pos_.at(0);
QPointF rubberband_now_scaled = fv->UnscalePoint(fv->mapToScene(fv->mapFromGlobal(rubberband_now)));

QPoint rubberband_local_start = fv->mapTo(this, fv->mapFromScene(fv->ScalePoint(rubberband_scene_start)));
QPoint rubberband_local_now = fv->mapTo(this, fv->mapFromScene(fv->ScalePoint(rubberband_now_scaled)));

rubberband_.setGeometry(QRect(rubberband_local_start, rubberband_local_now).normalized());

rubberband_enable_selecting_ = enable_selecting;
rubberband_select_links_ = select_links;

if (!enable_selecting) {
return;
}

// Get current items in rubberband
QVector<Block*> items_in_rubberband = GetBlocksInGlobalRect(drag_origin_, rubberband_now);
QVector<Block*> items_in_rubberband;

for (int i = 0; i < views_.size(); i++) {
TimelineView *v = views_.at(i)->view();
QRectF r = QRectF(v->ScalePoint(rubberband_scene_pos_.at(i)), v->mapToScene(v->mapFromGlobal(rubberband_now))).normalized();
items_in_rubberband.append(v->GetItemsAtSceneRect(r));
}

// Reset selection to whatever it was before
SetSelections(rubberband_old_selections_, false);
Expand Down
12 changes: 8 additions & 4 deletions app/widget/timelinewidget/timelinewidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,9 @@ public slots:

virtual const QVector<Block*> *GetSnapBlocks() const override { return &added_blocks_; }

protected slots:
virtual void SendCatchUpScrollEvent() override;

private:
QVector<Timeline::EditToInfo> GetEditToInfo(const rational &playhead_time, Timeline::MovementMode mode);

Expand All @@ -308,19 +311,18 @@ public slots:

void UpdateViewports(const Track::Type& type = Track::kNone);

QVector<Block*> GetBlocksInGlobalRect(const QPoint &p1, const QPoint &p2);

bool PasteInternal(bool insert);

TimelineAndTrackView *AddTimelineAndTrackView(Qt::Alignment alignment);

QHash<Node*, Node*> GenerateExistingPasteMap(const ProjectSerializer::Result &r);

QPoint drag_origin_;

QRubberBand rubberband_;
QVector<QPointF> rubberband_scene_pos_;
TimelineWidgetSelections rubberband_old_selections_;
QVector<Block*> rubberband_now_selected_;
bool rubberband_enable_selecting_;
bool rubberband_select_links_;

TimelineWidgetSelections selections_;

Expand Down Expand Up @@ -446,6 +448,8 @@ private slots:

void MulticamEnabledTriggered(bool e);

void ForceUpdateRubberBand();

};

}
Expand Down
28 changes: 28 additions & 0 deletions app/widget/timelinewidget/view/timelineview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,34 @@ Block *TimelineView::GetItemAtScenePos(const rational &time, int track_index) co
return nullptr;
}

QVector<Block *> TimelineView::GetItemsAtSceneRect(const QRectF &rect) const
{
QVector<Block *> list;

if (connected_track_list_) {
rational start = this->SceneToTime(rect.left());
rational end = this->SceneToTime(rect.right());

for (int i = 0; i < connected_track_list_->GetTrackCount(); i++) {
Track *track = connected_track_list_->GetTrackAt(i);
int track_top = GetTrackY(i);
int track_bottom = track_top + GetTrackHeight(i);

if (track) {
if (!(track_bottom < rect.top() || track_top > rect.bottom())) {
Block *b = track->NearestBlockBeforeOrAt(start);
while (b && b->in() < end) {
list.append(b);
b = b->next();
}
}
}
}
}

return list;
}

void TimelineView::TrackListChanged()
{
UpdateSceneRect();
Expand Down
2 changes: 2 additions & 0 deletions app/widget/timelinewidget/view/timelineview.h
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class TimelineView : public TimeBasedView

Block* GetItemAtScenePos(const rational& time, int track_index) const;

QVector<Block*> GetItemsAtSceneRect(const QRectF &rect) const;

signals:
void MousePressed(TimelineViewMouseEvent* event);
void MouseMoved(TimelineViewMouseEvent* event);
Expand Down

0 comments on commit d0f16ef

Please sign in to comment.