scroll_area.h 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. // This file is part of Desktop App Toolkit,
  2. // a set of libraries for developing nice desktop applications.
  3. //
  4. // For license and copyright information please follow this link:
  5. // https://github.com/desktop-app/legal/blob/master/LEGAL
  6. //
  7. #pragma once
  8. #include "ui/rp_widget.h"
  9. #include "ui/effects/animations.h"
  10. #include "base/object_ptr.h"
  11. #include "base/timer.h"
  12. #include "styles/style_widgets.h"
  13. #include <QtWidgets/QScrollArea>
  14. #include <QtGui/QtEvents>
  15. namespace Ui {
  16. // Touch flick ignore 3px.
  17. inline constexpr auto kFingerAccuracyThreshold = 3;
  18. // 4000px per second.
  19. inline constexpr auto kMaxScrollAccelerated = 4000;
  20. // 2500px per second.
  21. inline constexpr auto kMaxScrollFlick = 2500;
  22. enum class TouchScrollState {
  23. Manual, // Scrolling manually with the finger on the screen
  24. Auto, // Scrolling automatically
  25. Acceleration // Scrolling automatically but a finger is on the screen
  26. };
  27. class ScrollArea;
  28. struct ScrollToRequest {
  29. ScrollToRequest(int ymin, int ymax)
  30. : ymin(ymin)
  31. , ymax(ymax) {
  32. }
  33. int ymin = 0;
  34. int ymax = 0;
  35. };
  36. class ScrollShadow final : public QWidget {
  37. public:
  38. enum class Type {
  39. Top,
  40. Bottom,
  41. };
  42. ScrollShadow(ScrollArea *parent, const style::ScrollArea *st);
  43. void paintEvent(QPaintEvent *e);
  44. void changeVisibility(bool shown);
  45. private:
  46. const style::ScrollArea *_st;
  47. };
  48. class ScrollBar : public TWidget {
  49. public:
  50. struct ShadowVisibility {
  51. ScrollShadow::Type type;
  52. bool visible = false;
  53. };
  54. ScrollBar(ScrollArea *parent, bool vertical, const style::ScrollArea *st);
  55. void recountSize();
  56. void updateBar(bool force = false);
  57. void hideTimeout(crl::time dt);
  58. [[nodiscard]] auto shadowVisibilityChanged() const
  59. -> rpl::producer<ShadowVisibility>;
  60. protected:
  61. void paintEvent(QPaintEvent *e) override;
  62. void enterEventHook(QEnterEvent *e) override;
  63. void leaveEventHook(QEvent *e) override;
  64. void mouseMoveEvent(QMouseEvent *e) override;
  65. void mousePressEvent(QMouseEvent *e) override;
  66. void mouseReleaseEvent(QMouseEvent *e) override;
  67. void resizeEvent(QResizeEvent *e) override;
  68. void wheelEvent(QWheelEvent *e) override;
  69. private:
  70. ScrollArea *area();
  71. void setOver(bool over);
  72. void setOverBar(bool overbar);
  73. void setMoving(bool moving);
  74. void hideTimer();
  75. const style::ScrollArea *_st;
  76. bool _vertical = true;
  77. bool _hiding = false;
  78. bool _over = false;
  79. bool _overbar = false;
  80. bool _moving = false;
  81. bool _topSh = false;
  82. bool _bottomSh = false;
  83. QPoint _dragStart;
  84. QScrollBar *_connected;
  85. int32 _startFrom, _scrollMax;
  86. crl::time _hideIn = 0;
  87. base::Timer _hideTimer;
  88. Animations::Simple _a_over;
  89. Animations::Simple _a_barOver;
  90. Animations::Simple _a_opacity;
  91. QRect _bar;
  92. rpl::event_stream<ShadowVisibility> _shadowVisibilityChanged;
  93. };
  94. class ScrollArea : public RpWidgetBase<QScrollArea> {
  95. public:
  96. using Parent = RpWidgetBase<QScrollArea>;
  97. ScrollArea(QWidget *parent, const style::ScrollArea &st = st::defaultScrollArea, bool handleTouch = true);
  98. int scrollWidth() const;
  99. int scrollHeight() const;
  100. int scrollLeftMax() const;
  101. int scrollTopMax() const;
  102. int scrollLeft() const;
  103. int scrollTop() const;
  104. template <typename Widget>
  105. QPointer<Widget> setOwnedWidget(object_ptr<Widget> widget) {
  106. auto result = QPointer<Widget>(widget);
  107. doSetOwnedWidget(std::move(widget));
  108. return result;
  109. }
  110. template <typename Widget>
  111. object_ptr<Widget> takeWidget() {
  112. return object_ptr<Widget>::fromRaw(
  113. static_cast<Widget*>(doTakeWidget().release()));
  114. }
  115. void rangeChanged(int oldMax, int newMax, bool vertical);
  116. void updateBars();
  117. bool focusNextPrevChild(bool next) override;
  118. void setMovingByScrollBar(bool movingByScrollBar);
  119. bool viewportEvent(QEvent *e) override;
  120. void keyPressEvent(QKeyEvent *e) override;
  121. auto scrollTopValue() const {
  122. return _scrollTopUpdated.events_starting_with(scrollTop());
  123. }
  124. auto scrollTopChanges() const {
  125. return _scrollTopUpdated.events();
  126. }
  127. void scrollTo(ScrollToRequest request);
  128. void scrollToWidget(not_null<QWidget*> widget);
  129. [[nodiscard]] int computeScrollToX(int toLeft, int toRight);
  130. [[nodiscard]] int computeScrollToY(int toTop, int toBottom);
  131. void scrollToX(int toLeft, int toRight = -1);
  132. void scrollToY(int toTop, int toBottom = -1);
  133. void disableScroll(bool dis);
  134. void scrolled();
  135. void innerResized();
  136. void setCustomWheelProcess(Fn<bool(not_null<QWheelEvent*>)> process) {
  137. _customWheelProcess = std::move(process);
  138. }
  139. void setCustomTouchProcess(Fn<bool(not_null<QTouchEvent*>)> process) {
  140. _customTouchProcess = std::move(process);
  141. }
  142. [[nodiscard]] rpl::producer<> scrolls() const;
  143. [[nodiscard]] rpl::producer<> innerResizes() const;
  144. [[nodiscard]] rpl::producer<> geometryChanged() const;
  145. [[nodiscard]] rpl::producer<bool> touchMaybePressing() const;
  146. protected:
  147. bool eventHook(QEvent *e) override;
  148. bool eventFilter(QObject *obj, QEvent *e) override;
  149. void resizeEvent(QResizeEvent *e) override;
  150. void moveEvent(QMoveEvent *e) override;
  151. void touchEvent(QTouchEvent *e);
  152. void enterEventHook(QEnterEvent *e) override;
  153. void leaveEventHook(QEvent *e) override;
  154. protected:
  155. void scrollContentsBy(int dx, int dy) override;
  156. private:
  157. void doSetOwnedWidget(object_ptr<QWidget> widget);
  158. object_ptr<QWidget> doTakeWidget();
  159. bool filterOutTouchEvent(QEvent *e);
  160. void touchScrollTimer();
  161. bool touchScroll(const QPoint &delta);
  162. void touchScrollUpdated(const QPoint &screenPos);
  163. void touchResetSpeed();
  164. void touchUpdateSpeed();
  165. void touchDeaccelerate(int32 elapsed);
  166. bool _disabled = false;
  167. bool _movingByScrollBar = false;
  168. const style::ScrollArea &_st;
  169. object_ptr<ScrollBar> _horizontalBar, _verticalBar;
  170. object_ptr<ScrollShadow> _topShadow, _bottomShadow;
  171. int _horizontalValue, _verticalValue;
  172. bool _touchEnabled = false;
  173. base::Timer _touchTimer;
  174. bool _touchScroll = false;
  175. bool _touchPress = false;
  176. bool _touchRightButton = false;
  177. QPoint _touchStart, _touchPrevPos, _touchPos;
  178. TouchScrollState _touchScrollState = TouchScrollState::Manual;
  179. bool _touchPrevPosValid = false;
  180. bool _touchWaitingAcceleration = false;
  181. rpl::variable<bool> _touchMaybePressing;
  182. QPoint _touchSpeed;
  183. crl::time _touchSpeedTime = 0;
  184. crl::time _touchAccelerationTime = 0;
  185. crl::time _touchTime = 0;
  186. base::Timer _touchScrollTimer;
  187. Fn<bool(not_null<QWheelEvent*>)> _customWheelProcess;
  188. Fn<bool(not_null<QTouchEvent*>)> _customTouchProcess;
  189. bool _widgetAcceptsTouch = false;
  190. object_ptr<QWidget> _widget = { nullptr };
  191. rpl::event_stream<int> _scrollTopUpdated;
  192. rpl::event_stream<> _scrolls;
  193. rpl::event_stream<> _innerResizes;
  194. rpl::event_stream<> _geometryChanged;
  195. };
  196. } // namespace Ui