From d1619b728e89c40c6d66332df50e81f8dabaff97 Mon Sep 17 00:00:00 2001 From: 23rd <23rd@vivaldi.net> Date: Sat, 28 Mar 2020 17:17:32 +0300 Subject: [PATCH] Added ability to scroll vertical layout during reordering. --- ui/wrap/vertical_layout_reorder.cpp | 53 +++++++++++++++++++++++++++-- ui/wrap/vertical_layout_reorder.h | 12 ++++++- 2 files changed, 62 insertions(+), 3 deletions(-) diff --git a/ui/wrap/vertical_layout_reorder.cpp b/ui/wrap/vertical_layout_reorder.cpp index e312114..ed97b06 100644 --- a/ui/wrap/vertical_layout_reorder.cpp +++ b/ui/wrap/vertical_layout_reorder.cpp @@ -14,9 +14,18 @@ namespace Ui { +namespace { + +constexpr auto kScrollFactor = 0.05; + +} // namespace + VerticalLayoutReorder::VerticalLayoutReorder( - not_null layout) -: _layout(layout) { + not_null layout, + not_null scroll) +: _layout(layout) +, _scroll(scroll) +, _scrollAnimation([=] { updateScrollCallback(); }) { } void VerticalLayoutReorder::cancel() { @@ -100,6 +109,8 @@ void VerticalLayoutReorder::updateOrder(int index, QPoint position) { current.shift = current.finalShift = shift; _layout->setVerticalShift(index, shift); + checkForScrollAnimation(); + const auto count = _entries.size(); const auto currentHeight = current.widget->height(); const auto currentMiddle = current.widget->y() + currentHeight / 2; @@ -153,6 +164,7 @@ void VerticalLayoutReorder::mouseRelease( if (button != Qt::LeftButton) { return; } + _scrollAnimation.stop(); finishCurrent(); } @@ -267,4 +279,41 @@ auto VerticalLayoutReorder::updates() const -> rpl::producer { return _updates.events(); } +void VerticalLayoutReorder::updateScrollCallback() { + const auto delta = deltaFromEdge(); + const auto oldTop = _scroll->scrollTop(); + _scroll->scrollToY(oldTop + delta); + const auto newTop = _scroll->scrollTop(); + + _currentStart += oldTop - newTop; + if (newTop == 0 || newTop == _scroll->scrollTopMax()) { + _scrollAnimation.stop(); + } +} + +void VerticalLayoutReorder::checkForScrollAnimation() { + if (!deltaFromEdge() || _scrollAnimation.animating()) { + return; + } + _scrollAnimation.start(); +} + +int VerticalLayoutReorder::deltaFromEdge() { + Expects(_currentWidget != nullptr); + + const auto globalPosition = _currentWidget->mapToGlobal(QPoint(0, 0)); + const auto localTop = _scroll->mapFromGlobal(globalPosition).y(); + const auto localBottom = localTop + + _currentWidget->height() + - _scroll->height(); + + const auto isTopEdge = (localTop < 0); + const auto isBottomEdge = (localBottom > 0); + if (!isTopEdge && !isBottomEdge) { + _scrollAnimation.stop(); + return 0; + } + return int((isBottomEdge ? localBottom : localTop) * kScrollFactor); +} + } // namespace Ui diff --git a/ui/wrap/vertical_layout_reorder.h b/ui/wrap/vertical_layout_reorder.h index d5e6769..27e62af 100644 --- a/ui/wrap/vertical_layout_reorder.h +++ b/ui/wrap/vertical_layout_reorder.h @@ -7,6 +7,7 @@ #pragma once #include "ui/effects/animations.h" +#include "ui/widgets/scroll_area.h" namespace Ui { @@ -27,7 +28,9 @@ public: State state = State::Started; }; - VerticalLayoutReorder(not_null layout); + VerticalLayoutReorder( + not_null layout, + not_null scroll); void start(); void cancel(); @@ -59,7 +62,14 @@ private: void moveToShift(int index, int shift); void updateShift(not_null widget, int indexHint); + void updateScrollCallback(); + void checkForScrollAnimation(); + int deltaFromEdge(); + const not_null _layout; + const not_null _scroll; + + Ui::Animations::Basic _scrollAnimation; RpWidget *_currentWidget = nullptr; int _currentStart = 0;