From 081d1725afa92fc2a4b1988624e8ac79563956d9 Mon Sep 17 00:00:00 2001 From: John Preston Date: Mon, 10 Jul 2023 11:06:56 +0400 Subject: [PATCH] Fix scrolling by scrollbar drag. --- ui/widgets/elastic_scroll.cpp | 24 +++++++++++++++++++----- ui/widgets/elastic_scroll.h | 1 + 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/ui/widgets/elastic_scroll.cpp b/ui/widgets/elastic_scroll.cpp index adbbc49..9019a01 100644 --- a/ui/widgets/elastic_scroll.cpp +++ b/ui/widgets/elastic_scroll.cpp @@ -53,21 +53,24 @@ void ElasticScrollBar::refreshGeometry() { return; } const auto available = extSize - fullSkip; - const auto scale = [&](int value) { - return (available * value) / _state.fullSize; - }; - _area = _vertical ? QRect(skip, _st.deltat, thickness, available) : QRect(_st.deltat, skip, available, thickness); const auto barMin = std::min(st::scrollBarMin, available / 2); - const auto barWanted = scale(_state.visibleTill - _state.visibleFrom); + const auto visibleHeight = _state.visibleTill - _state.visibleFrom; + const auto scrollableHeight = _state.fullSize - visibleHeight; + const auto barWanted = (available * visibleHeight) / _state.fullSize; if (barWanted >= available) { _bar = _area = QRect(); hide(); return; } const auto bar = std::max(barMin, barWanted); + const auto outsideBar = available - bar; + + const auto scale = [&](int value) { + return (outsideBar * value) / scrollableHeight; + }; const auto barFrom = scale(_state.visibleFrom); const auto barTill = barFrom + bar; const auto cutFrom = std::clamp(barFrom, 0, available - thickness); @@ -224,6 +227,16 @@ void ElasticScrollBar::leaveEventHook(QEvent *e) { } } +int ElasticScrollBar::scaleToBar(int change) const { + const auto scrollable = _state.fullSize + - (_state.visibleTill - _state.visibleFrom); + const auto outsideBar = (_vertical ? _area.height() : _area.width()) + - (_vertical ? _bar.height() : _bar.width()); + return (outsideBar <= 0 || scrollable <= outsideBar) + ? change + : (change * scrollable / outsideBar); +} + void ElasticScrollBar::mouseMoveEvent(QMouseEvent *e) { toggleOverBar(_bar.contains(e->pos())); if (_dragging && !_bar.isEmpty()) { @@ -231,6 +244,7 @@ void ElasticScrollBar::mouseMoveEvent(QMouseEvent *e) { const auto delta = position - _dragPosition; _dragPosition = position; if (auto change = _vertical ? delta.y() : delta.x()) { + change = scaleToBar(change); if (_dragOverscrollAccumulated * change < 0) { const auto overscroll = (change < 0) ? std::max(_dragOverscrollAccumulated + change, 0) diff --git a/ui/widgets/elastic_scroll.h b/ui/widgets/elastic_scroll.h index 58f2144..a34a4d3 100644 --- a/ui/widgets/elastic_scroll.h +++ b/ui/widgets/elastic_scroll.h @@ -56,6 +56,7 @@ private: void leaveEventHook(QEvent *e) override; void resizeEvent(QResizeEvent *e) override; + [[nodiscard]] int scaleToBar(int change) const; [[nodiscard]] bool barHighlighted() const; void toggleOver(bool over, anim::type animated = anim::type::normal); void toggleOverBar(bool over, anim::type animated = anim::type::normal);