From bc2dec3dfebecd6f4f7016daedd8f44cd47f73a1 Mon Sep 17 00:00:00 2001 From: Darby Johnston Date: Tue, 16 Apr 2024 13:39:29 -0700 Subject: [PATCH] Scrolling fixes --- lib/tlTimelineUI/IItem.cpp | 44 ++++++++++++++--------------- lib/tlTimelineUI/IItem.h | 9 ++++-- lib/tlTimelineUI/TimelineItem.cpp | 28 +++++++++--------- lib/tlTimelineUI/TimelineWidget.cpp | 25 +++++++++++----- 4 files changed, 60 insertions(+), 46 deletions(-) diff --git a/lib/tlTimelineUI/IItem.cpp b/lib/tlTimelineUI/IItem.cpp index ded54bbb..5717ee37 100644 --- a/lib/tlTimelineUI/IItem.cpp +++ b/lib/tlTimelineUI/IItem.cpp @@ -178,27 +178,7 @@ namespace tl _updates |= ui::Update::Draw; } - math::Box2i IItem::_getClipRect( - const math::Box2i& value, - double scale) - { - math::Box2i out; - const math::Vector2i c = value.getCenter(); - out.min.x = (value.min.x - c.x) * scale + c.x; - out.min.y = (value.min.y - c.y) * scale + c.y; - out.max.x = (value.max.x - c.x) * scale + c.x; - out.max.y = (value.max.y - c.y) * scale + c.y; - return out; - } - - std::string IItem::_getDurationLabel(const otime::RationalTime& value) - { - const otime::RationalTime rescaled = value.rescaled_to(_data->speed); - return string::Format("{0}"). - arg(_data->timeUnitsModel->getLabel(rescaled)); - } - - otime::RationalTime IItem::_posToTime(float value) const + otime::RationalTime IItem::posToTime(float value) const { otime::RationalTime out = time::invalidTime; if (_geometry.w() > 0) @@ -218,12 +198,32 @@ namespace tl return out; } - int IItem::_timeToPos(const otime::RationalTime& value) const + int IItem::timeToPos(const otime::RationalTime& value) const { const otime::RationalTime t = value - _timeRange.start_time(); return _geometry.min.x + t.rescaled_to(1.0).value() * _scale; } + math::Box2i IItem::_getClipRect( + const math::Box2i& value, + double scale) + { + math::Box2i out; + const math::Vector2i c = value.getCenter(); + out.min.x = (value.min.x - c.x) * scale + c.x; + out.min.y = (value.min.y - c.y) * scale + c.y; + out.max.x = (value.max.x - c.x) * scale + c.x; + out.max.y = (value.max.y - c.y) * scale + c.y; + return out; + } + + std::string IItem::_getDurationLabel(const otime::RationalTime& value) + { + const otime::RationalTime rescaled = value.rescaled_to(_data->speed); + return string::Format("{0}"). + arg(_data->timeUnitsModel->getLabel(rescaled)); + } + void IItem::_timeUnitsUpdate() {} } diff --git a/lib/tlTimelineUI/IItem.h b/lib/tlTimelineUI/IItem.h index 4a32e65c..f1d4651e 100644 --- a/lib/tlTimelineUI/IItem.h +++ b/lib/tlTimelineUI/IItem.h @@ -139,6 +139,12 @@ namespace tl //! Set the selection color role. void setSelectRole(ui::ColorRole); + //! Convert a position to a time. + otime::RationalTime posToTime(float) const; + + //! Convert a time to a position. + int timeToPos(const otime::RationalTime&) const; + protected: static math::Box2i _getClipRect( const math::Box2i&, @@ -146,9 +152,6 @@ namespace tl std::string _getDurationLabel(const otime::RationalTime&); - otime::RationalTime _posToTime(float) const; - int _timeToPos(const otime::RationalTime&) const; - virtual void _timeUnitsUpdate(); otime::TimeRange _timeRange = time::invalidTimeRange; diff --git a/lib/tlTimelineUI/TimelineItem.cpp b/lib/tlTimelineUI/TimelineItem.cpp index 16551a48..9d90a102 100644 --- a/lib/tlTimelineUI/TimelineItem.cpp +++ b/lib/tlTimelineUI/TimelineItem.cpp @@ -433,7 +433,7 @@ namespace tl { case Private::MouseMode::CurrentTime: { - const otime::RationalTime time = _posToTime(event.pos.x); + const otime::RationalTime time = posToTime(event.pos.x); p.timeScrub->setIfChanged(time); p.player->seek(time); break; @@ -533,7 +533,7 @@ namespace tl { p.player->setPlayback(timeline::Playback::Stop); } - const otime::RationalTime time = _posToTime(event.pos.x); + const otime::RationalTime time = posToTime(event.pos.x); p.scrub->setIfChanged(true); p.timeScrub->setIfChanged(time); p.player->seek(time); @@ -627,8 +627,8 @@ namespace tl { case InOutDisplay::InsideRange: { - const int x0 = _timeToPos(_p->inOutRange.start_time()); - const int x1 = _timeToPos(_p->inOutRange.end_time_exclusive()); + const int x0 = timeToPos(_p->inOutRange.start_time()); + const int x1 = timeToPos(_p->inOutRange.end_time_exclusive()); const math::Box2i box( x0, p.size.scrollPos.y + @@ -644,8 +644,8 @@ namespace tl } case InOutDisplay::OutsideRange: { - int x0 = _timeToPos(_timeRange.start_time()); - int x1 = _timeToPos(_p->inOutRange.start_time()); + int x0 = timeToPos(_timeRange.start_time()); + int x1 = timeToPos(_p->inOutRange.start_time()); math::Box2i box( x0, p.size.scrollPos.y + @@ -657,8 +657,8 @@ namespace tl event.render->drawRect( box, event.style->getColorRole(ui::ColorRole::InOut)); - x0 = _timeToPos(_p->inOutRange.end_time_exclusive()); - x1 = _timeToPos(_timeRange.end_time_exclusive()); + x0 = timeToPos(_p->inOutRange.end_time_exclusive()); + x1 = timeToPos(_timeRange.end_time_exclusive()); box = math::Box2i( x0, p.size.scrollPos.y + @@ -816,7 +816,7 @@ namespace tl for (const auto& frameMarker : p.frameMarkers) { const math::Box2i g2( - _timeToPos(otime::RationalTime(frameMarker, rate)), + timeToPos(otime::RationalTime(frameMarker, rate)), p.size.scrollPos.y + g.min.y, p.size.border * 2, @@ -894,8 +894,8 @@ namespace tl size_t i = 1; for (const auto& t : p.cacheInfo.videoFrames) { - const int x0 = _timeToPos(t.start_time()); - const int x1 = _timeToPos(t.end_time_exclusive()); + const int x0 = timeToPos(t.start_time()); + const int x1 = timeToPos(t.end_time_exclusive()); const int h = CacheDisplay::VideoAndAudio == _options.cacheDisplay ? p.size.border * 2 : p.size.border * 4; @@ -934,8 +934,8 @@ namespace tl size_t i = 1; for (const auto& t : p.cacheInfo.audioFrames) { - const int x0 = _timeToPos(t.start_time()); - const int x1 = _timeToPos(t.end_time_exclusive()); + const int x0 = timeToPos(t.start_time()); + const int x1 = timeToPos(t.end_time_exclusive()); const math::Box2i box( x0, p.size.scrollPos.y + @@ -978,7 +978,7 @@ namespace tl if (!time::compareExact(p.currentTime, time::invalidTime)) { const math::Vector2i pos( - _timeToPos(p.currentTime), + timeToPos(p.currentTime), p.size.scrollPos.y + g.min.y); diff --git a/lib/tlTimelineUI/TimelineWidget.cpp b/lib/tlTimelineUI/TimelineWidget.cpp index 18d3a014..af0e7582 100644 --- a/lib/tlTimelineUI/TimelineWidget.cpp +++ b/lib/tlTimelineUI/TimelineWidget.cpp @@ -13,6 +13,11 @@ namespace tl { namespace timelineui { + namespace + { + const float marginPercentage = .1F; + } + struct TimelineWidget::Private { std::shared_ptr itemData; @@ -438,7 +443,6 @@ namespace tl IWidget::mouseReleaseEvent(event); TLRENDER_P(); p.mouse.mode = Private::MouseMode::None; - _scrollUpdate(); } void TimelineWidget::scrollEvent(ui::ScrollEvent& event) @@ -580,15 +584,22 @@ namespace tl void TimelineWidget::_scrollUpdate() { TLRENDER_P(); - if (p.scrollToCurrentFrame->get() && + if (p.timelineItem && + p.scrollToCurrentFrame->get() && !p.scrub->get() && Private::MouseMode::None == p.mouse.mode) { - const otime::RationalTime t = p.currentTime - p.timeRange.start_time(); - math::Vector2i scrollPos = p.scrollWidget->getScrollPos(); - scrollPos.x = _geometry.min.x - _geometry.w() / 2 + - t.rescaled_to(1.0).value() * p.scale; - p.scrollWidget->setScrollPos(scrollPos); + const int pos = p.timelineItem->timeToPos(p.currentTime); + const math::Box2i vp = p.scrollWidget->getViewport(); + const int margin = vp.w() * marginPercentage; + if (pos < (vp.min.x + margin) || pos >(vp.max.x - margin)) + { + const int offset = pos < (vp.min.x + margin) ? (vp.min.x + margin) : (vp.max.x - margin); + const otime::RationalTime t = p.currentTime - p.timeRange.start_time(); + math::Vector2i scrollPos = p.scrollWidget->getScrollPos(); + scrollPos.x = _geometry.min.x - offset + t.rescaled_to(1.0).value() * p.scale; + p.scrollWidget->setScrollPos(scrollPos); + } } }