@@ -8,6 +8,7 @@ For license and copyright information please follow this link:
88#include " info/info_flexible_scroll.h"
99
1010#include " ui/widgets/scroll_area.h"
11+ #include " base/event_filter.h"
1112#include " styles/style_info.h"
1213
1314#include < QtWidgets/QApplication>
@@ -29,7 +30,8 @@ FlexibleScrollHelper::FlexibleScrollHelper(
2930, _setViewport(setViewport)
3031, _data(data) {
3132 setupScrollAnimation ();
32- setupScrollHandling ();
33+ // setupScrollHandling();
34+ setupScrollHandlingWithFilter ();
3335}
3436
3537void FlexibleScrollHelper::setupScrollAnimation () {
@@ -195,4 +197,130 @@ void FlexibleScrollHelper::setupScrollHandling() {
195197 }));
196198}
197199
200+ void FlexibleScrollHelper::setupScrollHandlingWithFilter () {
201+ const auto heightDiff = [=] {
202+ return _pinnedToTop->maximumHeight ()
203+ - _pinnedToTop->minimumHeight ();
204+ };
205+
206+ rpl::combine (
207+ _pinnedToTop->heightValue (),
208+ _inner->heightValue ()
209+ ) | rpl::start_with_next ([=](int , int h) {
210+ _data.contentHeightValue .fire (h + heightDiff ());
211+ }, _pinnedToTop->lifetime ());
212+
213+ const auto singleStep = _scroll->verticalScrollBar ()->singleStep ()
214+ * QApplication::wheelScrollLines ();
215+ const auto step1 = (_pinnedToTop->maximumHeight ()
216+ < st::infoProfileTopBarHeightMax)
217+ ? (st::infoProfileTopBarStep2 + st::lineWidth)
218+ : st::infoProfileTopBarStep1;
219+ const auto step2 = st::infoProfileTopBarStep2;
220+
221+ base::install_event_filter (_scroll->verticalScrollBar (), [=](
222+ not_null<QEvent*> e) {
223+ if (e->type () != QEvent::Wheel) {
224+ return base::EventFilterResult::Continue;
225+ }
226+ const auto wheel = static_cast <QWheelEvent*>(e.get ());
227+ const auto delta = wheel->angleDelta ().y ();
228+ if (std::abs (delta) != 120 ) {
229+ return base::EventFilterResult::Continue;
230+ }
231+ const auto top = _scroll->scrollTop ();
232+ const auto diff = (delta > 0 ) ? -singleStep : singleStep;
233+ const auto previousValue = top;
234+ const auto targetTop = top + diff;
235+ const auto nextStep = (diff > 0 )
236+ ? ((previousValue == 0 )
237+ ? step1
238+ : (previousValue == step1)
239+ ? step2
240+ : -1 )
241+ : ((targetTop < step1)
242+ ? 0
243+ : (targetTop < step2)
244+ ? step1
245+ : -1 );
246+ if (_scrollAnimation.animating ()
247+ && ((_scrollTopTo > _scrollTopFrom) != (diff > 0 ))) {
248+ auto overriddenDirection = true ;
249+ if (_scrollTopTo > _scrollTopFrom) {
250+ if (_scrollTopTo == step1) {
251+ _scrollTopTo = 0 ;
252+ } else if (_scrollTopTo == step2) {
253+ _scrollTopTo = step1;
254+ } else {
255+ overriddenDirection = false ;
256+ }
257+ } else {
258+ if (_scrollTopTo == 0 ) {
259+ _scrollTopTo = step1;
260+ } else if (_scrollTopTo == step1) {
261+ _scrollTopTo = step2;
262+ } else {
263+ overriddenDirection = false ;
264+ }
265+ }
266+ if (overriddenDirection) {
267+ _timeOffset = crl::now () - _scrollAnimation.started ();
268+ _scrollTopFrom = _lastScrollApplied
269+ ? _lastScrollApplied
270+ : top;
271+ return base::EventFilterResult::Cancel;
272+ } else {
273+ _scrollAnimation.stop ();
274+ _scrollTopFrom = 0 ;
275+ _scrollTopTo = 0 ;
276+ _timeOffset = 0 ;
277+ _lastScrollApplied = 0 ;
278+ }
279+ }
280+ _scrollTopFrom = _lastScrollApplied ? _lastScrollApplied : top;
281+ if (!_scrollAnimation.animating ()) {
282+ _scrollTopTo = (nextStep != -1 ) ? nextStep : targetTop;
283+ _scrollAnimation.start ();
284+ } else {
285+ if (_scrollTopTo > _scrollTopFrom) {
286+ if (_scrollTopTo == step1) {
287+ _scrollTopTo = step2;
288+ } else {
289+ _scrollTopTo += diff;
290+ }
291+ } else {
292+ if (_scrollTopTo == step2) {
293+ _scrollTopTo = step1;
294+ } else if (_scrollTopTo == step1) {
295+ _scrollTopTo = 0 ;
296+ } else {
297+ _scrollTopTo += diff;
298+ }
299+ }
300+ _timeOffset = crl::now () - _scrollAnimation.started ();
301+ }
302+ return base::EventFilterResult::Cancel;
303+ }, _filterLifetime);
304+
305+ _scroll->scrollTopValue (
306+ ) | rpl::start_with_next ([=](int top) {
307+ const auto current = heightDiff () - top;
308+ _inner->moveToLeft (0 , std::min (0 , current));
309+ _pinnedToTop->resize (
310+ _pinnedToTop->width (),
311+ std::max (current + _pinnedToTop->minimumHeight (), 0 ));
312+ }, _inner->lifetime ());
313+
314+ _data.fillerWidthValue .events (
315+ ) | rpl::start_with_next ([=](int w) {
316+ _inner->resizeToWidth (w);
317+ }, _inner->lifetime ());
318+
319+ _setPaintPadding ({ 0 , _pinnedToTop->minimumHeight (), 0 , 0 });
320+ _setViewport (_pinnedToTop->events (
321+ ) | rpl::filter ([](not_null<QEvent*> e) {
322+ return e->type () == QEvent::Wheel;
323+ }));
324+ }
325+
198326} // namespace Info
0 commit comments