From d0f16ef88ea1179a1ab48d1ff24258672200886c Mon Sep 17 00:00:00 2001 From: itsmattkc <34096995+itsmattkc@users.noreply.github.com> Date: Tue, 28 Feb 2023 20:39:02 -0800 Subject: [PATCH] timeline: vastly improve behavior when scrolling and zooming --- app/widget/timebased/timebasedwidget.h | 6 +- app/widget/timelinewidget/timelinewidget.cpp | 91 +++++++++---------- app/widget/timelinewidget/timelinewidget.h | 12 ++- .../timelinewidget/view/timelineview.cpp | 28 ++++++ app/widget/timelinewidget/view/timelineview.h | 2 + 5 files changed, 87 insertions(+), 52 deletions(-) diff --git a/app/widget/timebased/timebasedwidget.h b/app/widget/timebased/timebasedwidget.h index 51e35dd77..157556c63 100644 --- a/app/widget/timebased/timebasedwidget.h +++ b/app/widget/timebased/timebasedwidget.h @@ -141,7 +141,6 @@ protected: void ConnectTimelineView(TimeBasedView* base); void SetCatchUpScrollValue(QScrollBar *b, int v, int maximum); - void SetCatchUpScrollValue(int v); void StopCatchUpScrollTimer(QScrollBar *b); virtual const QVector *GetSnapBlocks() const { return nullptr; } @@ -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 diff --git a/app/widget/timelinewidget/timelinewidget.cpp b/app/widget/timelinewidget/timelinewidget.cpp index 23bc574d7..44aba7b76 100644 --- a/app/widget/timelinewidget/timelinewidget.cpp +++ b/app/widget/timelinewidget/timelinewidget.cpp @@ -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) @@ -339,6 +343,15 @@ void TimelineWidget::DisconnectNodeEvent(ViewerOutput *n) } } +void TimelineWidget::SendCatchUpScrollEvent() +{ + super::SendCatchUpScrollEvent(); + + if (rubberband_.isVisible()) { + this->ForceUpdateRubberBand(); + } +} + void TimelineWidget::SelectAll() { QVector newly_selected_blocks; @@ -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); @@ -1912,46 +1932,6 @@ void TimelineWidget::UpdateViewports(const Track::Type &type) } } -QVector TimelineWidget::GetBlocksInGlobalRect(const QPoint &p1, const QPoint& p2) -{ - QVector blocks_in_rect; - - // Determine which tracks are in the rect - for (int i=0; iview(); - - // 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(i)); - - for (int j=0; jGetTrackCount(); 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()) { @@ -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(); @@ -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 items_in_rubberband = GetBlocksInGlobalRect(drag_origin_, rubberband_now); + QVector 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); diff --git a/app/widget/timelinewidget/timelinewidget.h b/app/widget/timelinewidget/timelinewidget.h index 4a49bcfb7..112fdc987 100644 --- a/app/widget/timelinewidget/timelinewidget.h +++ b/app/widget/timelinewidget/timelinewidget.h @@ -299,6 +299,9 @@ protected: virtual const QVector *GetSnapBlocks() const override { return &added_blocks_; } +protected slots: + virtual void SendCatchUpScrollEvent() override; + private: QVector GetEditToInfo(const rational &playhead_time, Timeline::MovementMode mode); @@ -308,19 +311,18 @@ private: void UpdateViewports(const Track::Type& type = Track::kNone); - QVector GetBlocksInGlobalRect(const QPoint &p1, const QPoint &p2); - bool PasteInternal(bool insert); TimelineAndTrackView *AddTimelineAndTrackView(Qt::Alignment alignment); QHash GenerateExistingPasteMap(const ProjectSerializer::Result &r); - QPoint drag_origin_; - QRubberBand rubberband_; + QVector rubberband_scene_pos_; TimelineWidgetSelections rubberband_old_selections_; QVector rubberband_now_selected_; + bool rubberband_enable_selecting_; + bool rubberband_select_links_; TimelineWidgetSelections selections_; @@ -446,6 +448,8 @@ private slots: void MulticamEnabledTriggered(bool e); + void ForceUpdateRubberBand(); + }; } diff --git a/app/widget/timelinewidget/view/timelineview.cpp b/app/widget/timelinewidget/view/timelineview.cpp index d5b6e77b1..306a82f21 100644 --- a/app/widget/timelinewidget/view/timelineview.cpp +++ b/app/widget/timelinewidget/view/timelineview.cpp @@ -867,6 +867,34 @@ Block *TimelineView::GetItemAtScenePos(const rational &time, int track_index) co return nullptr; } +QVector TimelineView::GetItemsAtSceneRect(const QRectF &rect) const +{ + QVector 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(); diff --git a/app/widget/timelinewidget/view/timelineview.h b/app/widget/timelinewidget/view/timelineview.h index a1e1698a9..103850566 100644 --- a/app/widget/timelinewidget/view/timelineview.h +++ b/app/widget/timelinewidget/view/timelineview.h @@ -73,6 +73,8 @@ public: Block* GetItemAtScenePos(const rational& time, int track_index) const; + QVector GetItemsAtSceneRect(const QRectF &rect) const; + signals: void MousePressed(TimelineViewMouseEvent* event); void MouseMoved(TimelineViewMouseEvent* event);