| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285 |
- // This file is part of Desktop App Toolkit,
- // a set of libraries for developing nice desktop applications.
- //
- // For license and copyright information please follow this link:
- // https://github.com/desktop-app/legal/blob/master/LEGAL
- //
- #pragma once
- #include "ui/widgets/scroll_area.h" // For helpers, like ScrollToRequest.
- #include "ui/effects/animations.h"
- #include "ui/rp_widget.h"
- #include "base/object_ptr.h"
- #include "base/timer.h"
- namespace style {
- struct ScrollArea;
- } // namespace style
- namespace st {
- extern const style::ScrollArea &defaultScrollArea;
- } // namespace st
- namespace Ui {
- struct ScrollState {
- int visibleFrom = 0;
- int visibleTill = 0;
- int fullSize = 0;
- friend inline constexpr auto operator<=>(
- const ScrollState &,
- const ScrollState &) = default;
- friend inline constexpr bool operator==(
- const ScrollState &,
- const ScrollState &) = default;
- };
- class ElasticScrollBar final : public RpWidget {
- public:
- ElasticScrollBar(
- QWidget *parent,
- const style::ScrollArea &st,
- Qt::Orientation orientation = Qt::Vertical);
- void updateState(ScrollState state);
- void toggle(bool shown, anim::type animated = anim::type::normal);
- [[nodiscard]] rpl::producer<int> visibleFromDragged() const;
- private:
- void paintEvent(QPaintEvent *e) override;
- void mousePressEvent(QMouseEvent *e) override;
- void mouseMoveEvent(QMouseEvent *e) override;
- void mouseReleaseEvent(QMouseEvent *e) override;
- void enterEventHook(QEnterEvent *e) override;
- void leaveEventHook(QEvent *e) override;
- void resizeEvent(QResizeEvent *e) override;
- bool eventHook(QEvent *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);
- void toggleDragging(
- bool dragging,
- anim::type animated = anim::type::normal);
- void startBarHighlightAnimation(bool wasHighlighted);
- void refreshGeometry();
- const style::ScrollArea &_st;
- Ui::Animations::Simple _shownAnimation;
- Ui::Animations::Simple _overAnimation;
- Ui::Animations::Simple _barHighlightAnimation;
- base::Timer _hideTimer;
- rpl::event_stream<int> _visibleFromDragged;
- int _dragOverscrollAccumulated = 0;
- QRect _area;
- QRect _bar;
- QPoint _dragPosition;
- ScrollState _state;
- bool _shown : 1 = false;
- bool _over : 1 = false;
- bool _overBar : 1 = false;
- bool _vertical : 1 = false;
- bool _dragging : 1 = false;
- };
- struct ElasticScrollPosition {
- int value = 0;
- int overscroll = 0;
- friend inline auto operator<=>(
- ElasticScrollPosition,
- ElasticScrollPosition) = default;
- friend inline bool operator==(
- ElasticScrollPosition,
- ElasticScrollPosition) = default;
- };
- enum class ElasticScrollMovement {
- None,
- Progress,
- Momentum,
- Returning,
- };
- class ElasticScroll final : public RpWidget {
- public:
- ElasticScroll(
- QWidget *parent,
- const style::ScrollArea &st = st::defaultScrollArea,
- Qt::Orientation orientation = Qt::Vertical);
- ~ElasticScroll();
- void setHandleTouch(bool handle);
- bool viewportEvent(QEvent *e);
- void keyPressEvent(QKeyEvent *e) override;
- QWidget *viewport() const; // Dummy.
- int scrollWidth() const;
- int scrollHeight() const;
- int scrollLeftMax() const;
- int scrollTopMax() const;
- int scrollLeft() const;
- int scrollTop() const;
- template <typename Widget>
- QPointer<Widget> setOwnedWidget(object_ptr<Widget> widget) {
- auto result = QPointer<Widget>(widget);
- doSetOwnedWidget(std::move(widget));
- return result;
- }
- template <typename Widget>
- object_ptr<Widget> takeWidget() {
- return object_ptr<Widget>::fromRaw(
- static_cast<Widget*>(doTakeWidget().release()));
- }
- void updateBars();
- auto scrollTopValue() const {
- return _scrollTopUpdated.events_starting_with(scrollTop());
- }
- auto scrollTopChanges() const {
- return _scrollTopUpdated.events();
- }
- void scrollTo(ScrollToRequest request);
- void scrollToWidget(not_null<QWidget*> widget);
- void scrollToY(int toTop, int toBottom = -1);
- void scrollTo(int toFrom, int toTill = -1);
- void disableScroll(bool dis);
- void innerResized();
- void setCustomWheelProcess(Fn<bool(not_null<QWheelEvent*>)> process) {
- _customWheelProcess = std::move(process);
- }
- void setCustomTouchProcess(Fn<bool(not_null<QTouchEvent*>)> process) {
- _customTouchProcess = std::move(process);
- }
- enum class OverscrollType : uchar {
- None,
- Virtual,
- Real,
- };
- void setOverscrollTypes(OverscrollType from, OverscrollType till);
- void setOverscrollDefaults(int from, int till, bool shift = false);
- void setOverscrollBg(QColor bg);
- [[nodiscard]] rpl::producer<> scrolls() const;
- [[nodiscard]] rpl::producer<> innerResizes() const;
- [[nodiscard]] rpl::producer<> geometryChanged() const;
- using Position = ElasticScrollPosition;
- [[nodiscard]] Position position() const;
- [[nodiscard]] rpl::producer<Position> positionValue() const;
- using Movement = ElasticScrollMovement;
- [[nodiscard]] Movement movement() const;
- [[nodiscard]] rpl::producer<Movement> movementValue() const;
- [[nodiscard]] rpl::producer<bool> touchMaybePressing() const;
- private:
- bool eventHook(QEvent *e) override;
- bool eventFilter(QObject *obj, QEvent *e) override;
- void resizeEvent(QResizeEvent *e) override;
- void moveEvent(QMoveEvent *e) override;
- void wheelEvent(QWheelEvent *e) override;
- void paintEvent(QPaintEvent *e) override;
- void enterEventHook(QEnterEvent *e) override;
- void leaveEventHook(QEvent *e) override;
- bool handleWheelEvent(not_null<QWheelEvent*> e, bool touch = false);
- void handleTouchEvent(QTouchEvent *e);
- void updateState();
- void setState(ScrollState state);
- [[nodiscard]] int willScrollTo(int position) const;
- void tryScrollTo(int position, bool synthMouseMove = true);
- void applyScrollTo(int position, bool synthMouseMove = true);
- void applyOverscroll(int overscroll);
- void doSetOwnedWidget(object_ptr<QWidget> widget);
- object_ptr<QWidget> doTakeWidget();
- bool filterOutTouchEvent(QEvent *e);
- void touchScrollTimer();
- void touchScrollUpdated();
- void sendWheelEvent(Qt::ScrollPhase phase, QPoint delta = {});
- void touchResetSpeed();
- void touchUpdateSpeed();
- void touchDeaccelerate(int32 elapsed);
- struct AccumulatedParts {
- int base = 0;
- int relative = 0;
- };
- [[nodiscard]] AccumulatedParts computeAccumulatedParts() const;
- [[nodiscard]] int currentOverscrollDefault() const;
- [[nodiscard]] int currentOverscrollDefaultAccumulated() const;
- void overscrollReturn();
- void overscrollReturnCancel();
- void overscrollCheckReturnFinish();
- bool overscrollFinish();
- void applyAccumulatedScroll();
- const style::ScrollArea &_st;
- std::unique_ptr<ElasticScrollBar> _bar;
- ScrollState _state;
- base::Timer _touchTimer;
- base::Timer _touchScrollTimer;
- QPoint _touchStart;
- QPoint _touchPreviousPosition;
- QPoint _touchPosition;
- QPoint _touchSpeed;
- crl::time _touchSpeedTime = 0;
- crl::time _touchAccelerationTime = 0;
- crl::time _touchTime = 0;
- crl::time _lastScroll = 0;
- rpl::variable<bool> _touchMaybePressing;
- TouchScrollState _touchScrollState = TouchScrollState::Manual;
- int _overscrollAccumulated = 0;
- int _ignoreMomentumFromOverscroll = 0;
- bool _touchDisabled : 1 = false;
- bool _touchScroll : 1 = false;
- bool _touchPress : 1 = false;
- bool _touchRightButton : 1 = false;
- bool _touchPreviousPositionValid : 1 = false;
- bool _touchWaitingAcceleration : 1 = false;
- bool _vertical : 1 = false;
- bool _widgetAcceptsTouch : 1 = false;
- bool _disabled : 1 = false;
- bool _dirtyState : 1 = false;
- bool _overscrollReturning : 1 = false;
- Fn<bool(not_null<QWheelEvent*>)> _customWheelProcess;
- Fn<bool(not_null<QTouchEvent*>)> _customTouchProcess;
- int _overscroll = 0;
- int _overscrollDefaultFrom = 0;
- int _overscrollDefaultTill = 0;
- OverscrollType _overscrollTypeFrom = OverscrollType::Real;
- OverscrollType _overscrollTypeTill = OverscrollType::Real;
- std::optional<QColor> _overscrollBg;
- Ui::Animations::Simple _overscrollReturnAnimation;
- rpl::variable<Position> _position;
- rpl::variable<Movement> _movement;
- object_ptr<QWidget> _widget = { nullptr };
- rpl::event_stream<int> _scrollTopUpdated;
- rpl::event_stream<> _scrolls;
- rpl::event_stream<> _innerResizes;
- rpl::event_stream<> _geometryChanged;
- };
- [[nodiscard]] int OverscrollFromAccumulated(int accumulated);
- [[nodiscard]] int OverscrollToAccumulated(int overscroll);
- } // namespace Ui
|