diff --git a/ui/widgets/scroll_area.cpp b/ui/widgets/scroll_area.cpp index fdb2b04..257dc3d 100644 --- a/ui/widgets/scroll_area.cpp +++ b/ui/widgets/scroll_area.cpp @@ -38,14 +38,18 @@ ScrollBar::ScrollBar(ScrollArea *parent, bool vert, const style::ScrollArea *st) , _vertical(vert) , _hiding(_st->hiding != 0) , _connected(vert ? parent->verticalScrollBar() : parent->horizontalScrollBar()) -, _scrollMax(_connected->maximum()) { +, _scrollMax(_connected->maximum()) +, _hideTimer([=] { hideTimer(); }) { recountSize(); - _hideTimer.setSingleShot(true); - connect(&_hideTimer, SIGNAL(timeout()), this, SLOT(onHideTimer())); - - connect(_connected, SIGNAL(valueChanged(int)), this, SLOT(onValueChanged())); - connect(_connected, SIGNAL(rangeChanged(int, int)), this, SLOT(onRangeChanged())); + connect(_connected, &QAbstractSlider::valueChanged, [=] { + area()->onScrolled(); + updateBar(); + }); + connect(_connected, &QAbstractSlider::rangeChanged, [=] { + area()->onInnerResized(); + updateBar(); + }); updateBar(); } @@ -54,16 +58,6 @@ void ScrollBar::recountSize() { setGeometry(_vertical ? QRect(style::RightToLeft() ? 0 : (area()->width() - _st->width), _st->deltat, _st->width, area()->height() - _st->deltat - _st->deltab) : QRect(_st->deltat, area()->height() - _st->width, area()->width() - _st->deltat - _st->deltab, _st->width)); } -void ScrollBar::onValueChanged() { - area()->onScrolled(); - updateBar(); -} - -void ScrollBar::onRangeChanged() { - area()->onInnerResized(); - updateBar(); -} - void ScrollBar::updateBar(bool force) { QRect newBar; if (_connected->maximum() != _scrollMax) { @@ -76,8 +70,18 @@ void ScrollBar::updateBar(bool force) { if (h >= rh || !area()->scrollTopMax() || rh < _st->minHeight) { if (!isHidden()) hide(); bool newTopSh = (_st->topsh < 0), newBottomSh = (_st->bottomsh < 0); - if (newTopSh != _topSh || force) topShadowVisibility(_topSh = newTopSh); - if (newBottomSh != _bottomSh || force) bottomShadowVisibility(_bottomSh = newBottomSh); + if (newTopSh != _topSh || force) { + _shadowVisibilityChanged.fire({ + .type = ScrollShadow::Type::Top, + .visible = (_topSh = newTopSh), + }); + } + if (newBottomSh != _bottomSh || force) { + _shadowVisibilityChanged.fire({ + .type = ScrollShadow::Type::Bottom, + .visible = (_bottomSh = newBottomSh), + }); + } return; } @@ -105,13 +109,23 @@ void ScrollBar::updateBar(bool force) { } if (_vertical) { bool newTopSh = (_st->topsh < 0) || (area()->scrollTop() > _st->topsh), newBottomSh = (_st->bottomsh < 0) || (area()->scrollTop() < area()->scrollTopMax() - _st->bottomsh); - if (newTopSh != _topSh || force) topShadowVisibility(_topSh = newTopSh); - if (newBottomSh != _bottomSh || force) bottomShadowVisibility(_bottomSh = newBottomSh); + if (newTopSh != _topSh || force) { + _shadowVisibilityChanged.fire({ + .type = ScrollShadow::Type::Top, + .visible = (_topSh = newTopSh), + }); + } + if (newBottomSh != _bottomSh || force) { + _shadowVisibilityChanged.fire({ + .type = ScrollShadow::Type::Bottom, + .visible = (_bottomSh = newBottomSh), + }); + } } if (isHidden()) show(); } -void ScrollBar::onHideTimer() { +void ScrollBar::hideTimer() { if (!_hiding) { _hiding = true; _a_opacity.start([this] { update(); }, 1., 0., _st->duration); @@ -162,7 +176,7 @@ void ScrollBar::setMoving(bool moving) { _a_over.start([this] { update(); }, nowOver ? 0. : 1., nowOver ? 1. : 0., _st->duration); } if (!nowOver && _st->hiding && !_hiding) { - _hideTimer.start(_hideIn); + _hideTimer.callOnce(_hideIn); } } } @@ -202,12 +216,12 @@ void ScrollBar::hideTimeout(crl::time dt) { } _hideIn = dt; if (!_moving) { - _hideTimer.start(_hideIn); + _hideTimer.callOnce(_hideIn); } } void ScrollBar::enterEventHook(QEvent *e) { - _hideTimer.stop(); + _hideTimer.cancel(); setMouseTracking(true); setOver(true); } @@ -219,7 +233,7 @@ void ScrollBar::leaveEventHook(QEvent *e) { setOver(false); setOverBar(false); if (_st->hiding && !_hiding) { - _hideTimer.start(_hideIn); + _hideTimer.callOnce(_hideIn); } } @@ -271,6 +285,11 @@ void ScrollBar::resizeEvent(QResizeEvent *e) { updateBar(); } +auto ScrollBar::shadowVisibilityChanged() const +-> rpl::producer { + return _shadowVisibilityChanged.events(); +} + ScrollArea::ScrollArea(QWidget *parent, const style::ScrollArea &st, bool handleTouch) : Parent(parent) , _st(st) @@ -282,16 +301,13 @@ ScrollArea::ScrollArea(QWidget *parent, const style::ScrollArea &st, bool handle setLayoutDirection(style::LayoutDirection()); setFocusPolicy(Qt::NoFocus); - connect( - _verticalBar, - &ScrollBar::topShadowVisibility, - _topShadow, - &ScrollShadow::changeVisibility); - connect( - _verticalBar, - &ScrollBar::bottomShadowVisibility, - _bottomShadow, - &ScrollShadow::changeVisibility); + _verticalBar->shadowVisibilityChanged( + ) | rpl::start_with_next([=](const ScrollBar::ShadowVisibility &data) { + ((data.type == ScrollShadow::Type::Top) + ? _topShadow + : _bottomShadow)->changeVisibility(data.visible); + }, _lifetime); + _verticalBar->updateBar(true); verticalScrollBar()->setSingleStep(style::ConvertScale(verticalScrollBar()->singleStep())); diff --git a/ui/widgets/scroll_area.h b/ui/widgets/scroll_area.h index c45c3df..a527fe3 100644 --- a/ui/widgets/scroll_area.h +++ b/ui/widgets/scroll_area.h @@ -9,6 +9,7 @@ #include "ui/rp_widget.h" #include "ui/effects/animations.h" #include "base/object_ptr.h" +#include "base/timer.h" #include "styles/style_widgets.h" #include @@ -50,6 +51,10 @@ struct ScrollToRequest { class ScrollShadow final : public QWidget { public: + enum class Type { + Top, + Bottom, + }; ScrollShadow(ScrollArea *parent, const style::ScrollArea *st); void paintEvent(QPaintEvent *e); @@ -61,9 +66,11 @@ private: }; class ScrollBar : public TWidget { - Q_OBJECT - public: + struct ShadowVisibility { + ScrollShadow::Type type; + bool visible = false; + }; ScrollBar(ScrollArea *parent, bool vertical, const style::ScrollArea *st); void recountSize(); @@ -71,14 +78,8 @@ public: void hideTimeout(crl::time dt); -private Q_SLOTS: - void onValueChanged(); - void onRangeChanged(); - void onHideTimer(); - -Q_SIGNALS: - void topShadowVisibility(bool); - void bottomShadowVisibility(bool); + [[nodiscard]] auto shadowVisibilityChanged() const + -> rpl::producer; protected: void paintEvent(QPaintEvent *e) override; @@ -96,6 +97,8 @@ private: void setOverBar(bool overbar); void setMoving(bool moving); + void hideTimer(); + const style::ScrollArea *_st; bool _vertical = true; @@ -112,13 +115,15 @@ private: int32 _startFrom, _scrollMax; crl::time _hideIn = 0; - QTimer _hideTimer; + base::Timer _hideTimer; Animations::Simple _a_over; Animations::Simple _a_barOver; Animations::Simple _a_opacity; QRect _bar; + + rpl::event_stream _shadowVisibilityChanged; }; class ScrollArea : public RpWidgetBase { @@ -239,6 +244,7 @@ private: object_ptr _widget = { nullptr }; rpl::event_stream _scrollTopUpdated; + rpl::lifetime _lifetime; };