diff --git a/ui/layers/box_content.cpp b/ui/layers/box_content.cpp index fdaa06c..1dc17f4 100644 --- a/ui/layers/box_content.cpp +++ b/ui/layers/box_content.cpp @@ -263,8 +263,21 @@ RectParts BoxContent::customCornersFilling() { } void BoxContent::scrollToY(int top, int bottom) { + scrollTo({ top, bottom }); +} + +void BoxContent::scrollTo(ScrollToRequest request, anim::type animated) { if (_scroll) { - _scroll->scrollToY(top, bottom); + const auto v = _scroll->computeScrollTo(request.ymin, request.ymax); + const auto now = _scroll->scrollTop(); + if (animated == anim::type::instant || v == now) { + _scrollAnimation.stop(); + _scroll->scrollToY(v); + } else { + _scrollAnimation.start([=] { + _scroll->scrollToY(_scrollAnimation.value(v)); + }, now, v, st::slideWrapDuration, anim::sineInOut); + } } } diff --git a/ui/layers/box_content.h b/ui/layers/box_content.h index d528bf1..ef94672 100644 --- a/ui/layers/box_content.h +++ b/ui/layers/box_content.h @@ -13,6 +13,7 @@ #include "ui/widgets/labels.h" #include "ui/layers/layer_widget.h" #include "ui/layers/show.h" +#include "ui/effects/animations.h" #include "ui/effects/animation_value.h" #include "ui/text/text_entity.h" #include "ui/rp_widget.h" @@ -59,6 +60,7 @@ class ScrollArea; class FlatLabel; class FadeShadow; class BoxContent; +struct ScrollToRequest; class BoxContentDelegate { public: @@ -213,6 +215,9 @@ public: void scrollByDraggingDelta(int delta); void scrollToY(int top, int bottom = -1); + void scrollTo( + ScrollToRequest request, + anim::type animated = anim::type::instant); void sendScrollViewportEvent(not_null event); [[nodiscard]] rpl::producer<> scrolls() const; [[nodiscard]] int scrollTop() const; @@ -309,6 +314,7 @@ private: object_ptr _bottomShadow = { nullptr }; Ui::DraggingScrollManager _draggingScroll; + Ui::Animations::Simple _scrollAnimation; rpl::event_stream<> _boxClosingStream; diff --git a/ui/widgets/scroll_area.cpp b/ui/widgets/scroll_area.cpp index 81fc8bf..ed5ce69 100644 --- a/ui/widgets/scroll_area.cpp +++ b/ui/widgets/scroll_area.cpp @@ -706,32 +706,48 @@ void ScrollArea::scrollToWidget(not_null widget) { } } -void ScrollArea::scrollToY(int toTop, int toBottom) { +int ScrollArea::computeScrollTo(int toTop, int toBottom) { if (const auto inner = widget()) { SendPendingMoveResizeEvents(inner); } SendPendingMoveResizeEvents(this); - int toMin = 0, toMax = scrollTopMax(); + const auto toMin = 0; + const auto toMax = scrollTopMax(); if (toTop < toMin) { toTop = toMin; } else if (toTop > toMax) { toTop = toMax; } - bool exact = (toBottom < 0); + const auto exact = (toBottom < 0); - int curTop = scrollTop(), curHeight = height(), curBottom = curTop + curHeight, scToTop = toTop; + const auto curTop = scrollTop(); + const auto curHeight = height(); + const auto curBottom = curTop + curHeight; + auto scToTop = toTop; if (!exact && toTop >= curTop) { - if (toBottom < toTop) toBottom = toTop; - if (toBottom <= curBottom) return; + if (toBottom < toTop) { + toBottom = toTop; + } + if (toBottom <= curBottom) { + return curTop; + } scToTop = toBottom - curHeight; - if (scToTop > toTop) scToTop = toTop; - if (scToTop == curTop) return; + if (scToTop > toTop) { + scToTop = toTop; + } + if (scToTop == curTop) { + return curTop; + } } else { scToTop = toTop; } - verticalScrollBar()->setValue(scToTop); + return scToTop; +} + +void ScrollArea::scrollToY(int toTop, int toBottom) { + verticalScrollBar()->setValue(computeScrollTo(toTop, toBottom)); } void ScrollArea::doSetOwnedWidget(object_ptr w) { diff --git a/ui/widgets/scroll_area.h b/ui/widgets/scroll_area.h index b1d03a2..25f7360 100644 --- a/ui/widgets/scroll_area.h +++ b/ui/widgets/scroll_area.h @@ -166,6 +166,7 @@ public: void scrollTo(ScrollToRequest request); void scrollToWidget(not_null widget); + [[nodiscard]] int computeScrollTo(int toTop, int toBottom); void scrollToY(int toTop, int toBottom = -1); void disableScroll(bool dis);