Process touch through wheel events.

This commit is contained in:
John Preston 2023-07-11 21:40:50 +04:00
parent 427fc4c8f7
commit 6af98c0802
2 changed files with 64 additions and 25 deletions

View file

@ -22,6 +22,7 @@ constexpr auto kOverscrollReturnDuration = crl::time(250);
constexpr auto kOverscrollPower = 0.6; constexpr auto kOverscrollPower = 0.6;
constexpr auto kOverscrollFromThreshold = -(1 << 30); constexpr auto kOverscrollFromThreshold = -(1 << 30);
constexpr auto kOverscrollTillThreshold = (1 << 30); constexpr auto kOverscrollTillThreshold = (1 << 30);
constexpr auto kTouchOverscrollMultiplier = 2;
[[nodiscard]] int OverscrollFromAccumulated(int accumulated) { [[nodiscard]] int OverscrollFromAccumulated(int accumulated) {
if (!accumulated) { if (!accumulated) {
@ -56,6 +57,7 @@ ElasticScrollBar::ElasticScrollBar(
, _hideTimer([=] { toggle(false); }) , _hideTimer([=] { toggle(false); })
, _shown(!_st.hiding) , _shown(!_st.hiding)
, _vertical(orientation == Qt::Vertical) { , _vertical(orientation == Qt::Vertical) {
setAttribute(Qt::WA_NoMousePropagation);
} }
void ElasticScrollBar::refreshGeometry() { void ElasticScrollBar::refreshGeometry() {
@ -329,6 +331,11 @@ void ElasticScrollBar::resizeEvent(QResizeEvent *e) {
refreshGeometry(); refreshGeometry();
} }
bool ElasticScrollBar::eventHook(QEvent *e) {
setAttribute(Qt::WA_NoMousePropagation, e->type() != QEvent::Wheel);
return RpWidget::eventHook(e);
}
ElasticScroll::ElasticScroll( ElasticScroll::ElasticScroll(
QWidget *parent, QWidget *parent,
const style::ScrollArea &st, const style::ScrollArea &st,
@ -371,8 +378,17 @@ void ElasticScroll::setHandleTouch(bool handle) {
} }
bool ElasticScroll::viewportEvent(QEvent *e) { bool ElasticScroll::viewportEvent(QEvent *e) {
return (e->type() == QEvent::Wheel) const auto type = e->type();
&& handleWheelEvent(static_cast<QWheelEvent*>(e)); if (type == QEvent::Wheel) {
return handleWheelEvent(static_cast<QWheelEvent*>(e));
} else if (type == QEvent::TouchBegin
|| type == QEvent::TouchUpdate
|| type == QEvent::TouchEnd
|| type == QEvent::TouchCancel) {
handleTouchEvent(static_cast<QTouchEvent*>(e));
return true;
}
return false;
} }
void ElasticScroll::touchDeaccelerate(int32 elapsed) { void ElasticScroll::touchDeaccelerate(int32 elapsed) {
@ -496,14 +512,18 @@ void ElasticScroll::touchScrollTimer() {
auto nowTime = crl::now(); auto nowTime = crl::now();
if (_touchScrollState == TouchScrollState::Acceleration && _touchWaitingAcceleration && (nowTime - _touchAccelerationTime) > 40) { if (_touchScrollState == TouchScrollState::Acceleration && _touchWaitingAcceleration && (nowTime - _touchAccelerationTime) > 40) {
_touchScrollState = TouchScrollState::Manual; _touchScrollState = TouchScrollState::Manual;
sendWheelEvent(Qt::ScrollEnd);
touchResetSpeed(); touchResetSpeed();
} else if (_touchScrollState == TouchScrollState::Auto || _touchScrollState == TouchScrollState::Acceleration) { } else if (_touchScrollState == TouchScrollState::Auto || _touchScrollState == TouchScrollState::Acceleration) {
int32 elapsed = int32(nowTime - _touchTime); int32 elapsed = int32(nowTime - _touchTime);
QPoint delta = _touchSpeed * elapsed / 1000; QPoint delta = _touchSpeed * elapsed / 1000;
bool hasScrolled = touchScroll(delta); sendWheelEvent(
_touchPress ? Qt::ScrollUpdate : Qt::ScrollMomentum,
delta);
if (_touchSpeed.isNull() || !hasScrolled) { if (_touchSpeed.isNull()) {
_touchScrollState = TouchScrollState::Manual; _touchScrollState = TouchScrollState::Manual;
sendWheelEvent(Qt::ScrollEnd);
_touchScroll = false; _touchScroll = false;
_touchScrollTimer.cancel(); _touchScrollTimer.cancel();
} else { } else {
@ -602,7 +622,7 @@ void ElasticScroll::paintEvent(QPaintEvent *e) {
} }
} }
bool ElasticScroll::handleWheelEvent(not_null<QWheelEvent*> e) { bool ElasticScroll::handleWheelEvent(not_null<QWheelEvent*> e, bool touch) {
if (_customWheelProcess if (_customWheelProcess
&& _customWheelProcess(static_cast<QWheelEvent*>(e.get()))) { && _customWheelProcess(static_cast<QWheelEvent*>(e.get()))) {
return true; return true;
@ -652,6 +672,9 @@ bool ElasticScroll::handleWheelEvent(not_null<QWheelEvent*> e) {
if (!delta) { if (!delta) {
return true; return true;
} }
if (touch) {
delta *= kTouchOverscrollMultiplier;
}
const auto accumulated = _overscrollAccumulated + delta; const auto accumulated = _overscrollAccumulated + delta;
const auto type = (accumulated < 0) const auto type = (accumulated < 0)
? _overscrollTypeFrom ? _overscrollTypeFrom
@ -726,7 +749,9 @@ void ElasticScroll::handleTouchEvent(QTouchEvent *e) {
switch (e->type()) { switch (e->type()) {
case QEvent::TouchBegin: { case QEvent::TouchBegin: {
if (_touchPress || e->touchPoints().isEmpty()) return; if (_touchPress || e->touchPoints().isEmpty()) {
return;
}
_touchPress = true; _touchPress = true;
if (_touchScrollState == TouchScrollState::Auto) { if (_touchScrollState == TouchScrollState::Auto) {
_touchScrollState = TouchScrollState::Acceleration; _touchScrollState = TouchScrollState::Acceleration;
@ -740,18 +765,23 @@ void ElasticScroll::handleTouchEvent(QTouchEvent *e) {
} }
_touchStart = _touchPreviousPosition = _touchPosition; _touchStart = _touchPreviousPosition = _touchPosition;
_touchRightButton = false; _touchRightButton = false;
sendWheelEvent(Qt::ScrollBegin);
} break; } break;
case QEvent::TouchUpdate: { case QEvent::TouchUpdate: {
if (!_touchPress) return; if (!_touchPress) {
if (!_touchScroll && (_touchPosition - _touchStart).manhattanLength() >= QApplication::startDragDistance()) { return;
}
if (!_touchScroll
&& ((_touchPosition - _touchStart).manhattanLength()
>= QApplication::startDragDistance())) {
_touchTimer.cancel(); _touchTimer.cancel();
_touchScroll = true; _touchScroll = true;
touchUpdateSpeed(); touchUpdateSpeed();
} }
if (_touchScroll) { if (_touchScroll) {
if (_touchScrollState == TouchScrollState::Manual) { if (_touchScrollState == TouchScrollState::Manual) {
touchScrollUpdated(_touchPosition); touchScrollUpdated();
} else if (_touchScrollState == TouchScrollState::Acceleration) { } else if (_touchScrollState == TouchScrollState::Acceleration) {
touchUpdateSpeed(); touchUpdateSpeed();
_touchAccelerationTime = crl::now(); _touchAccelerationTime = crl::now();
@ -763,7 +793,9 @@ void ElasticScroll::handleTouchEvent(QTouchEvent *e) {
} break; } break;
case QEvent::TouchEnd: { case QEvent::TouchEnd: {
if (!_touchPress) return; if (!_touchPress) {
return;
}
_touchPress = false; _touchPress = false;
auto weak = MakeWeak(this); auto weak = MakeWeak(this);
if (_touchScroll) { if (_touchScroll) {
@ -811,9 +843,12 @@ void ElasticScroll::handleTouchEvent(QTouchEvent *e) {
} }
} }
void ElasticScroll::touchScrollUpdated(const QPoint &screenPos) { void ElasticScroll::touchScrollUpdated() {
_touchPosition = screenPos; //touchScroll(_touchPosition - _touchPreviousPosition);
touchScroll(_touchPosition - _touchPreviousPosition); const auto phase = !_touchPress
? Qt::ScrollMomentum
: Qt::ScrollUpdate;
sendWheelEvent(phase, _touchPosition - _touchPreviousPosition);
touchUpdateSpeed(); touchUpdateSpeed();
} }
@ -958,15 +993,18 @@ void ElasticScroll::tryScrollTo(int position, bool synthMouseMove) {
applyScrollTo(willScrollTo(position), synthMouseMove); applyScrollTo(willScrollTo(position), synthMouseMove);
} }
bool ElasticScroll::touchScroll(const QPoint &delta) { void ElasticScroll::sendWheelEvent(Qt::ScrollPhase phase, QPoint delta) {
const auto scTop = scrollTop(); auto e = QWheelEvent(
const auto scMax = scrollTopMax(); mapFromGlobal(_touchPosition),
const auto scNew = std::clamp(scTop - delta.y(), 0, scMax); _touchPosition,
if (scNew == scTop) { delta,
return false; delta,
} Qt::NoButton,
scrollToY(scNew); QGuiApplication::keyboardModifiers(),
return true; phase,
false,
Qt::MouseEventSynthesizedByApplication);
handleWheelEvent(&e, true);
} }
void ElasticScroll::resizeEvent(QResizeEvent *e) { void ElasticScroll::resizeEvent(QResizeEvent *e) {

View file

@ -55,6 +55,7 @@ private:
void enterEventHook(QEnterEvent *e) override; void enterEventHook(QEnterEvent *e) override;
void leaveEventHook(QEvent *e) override; void leaveEventHook(QEvent *e) override;
void resizeEvent(QResizeEvent *e) override; void resizeEvent(QResizeEvent *e) override;
bool eventHook(QEvent *e) override;
[[nodiscard]] int scaleToBar(int change) const; [[nodiscard]] int scaleToBar(int change) const;
[[nodiscard]] bool barHighlighted() const; [[nodiscard]] bool barHighlighted() const;
@ -187,7 +188,7 @@ private:
void enterEventHook(QEnterEvent *e) override; void enterEventHook(QEnterEvent *e) override;
void leaveEventHook(QEvent *e) override; void leaveEventHook(QEvent *e) override;
void keyPressEvent(QKeyEvent *e) override; void keyPressEvent(QKeyEvent *e) override;
bool handleWheelEvent(not_null<QWheelEvent*> e); bool handleWheelEvent(not_null<QWheelEvent*> e, bool touch = false);
void handleTouchEvent(QTouchEvent *e); void handleTouchEvent(QTouchEvent *e);
void updateState(); void updateState();
@ -202,8 +203,8 @@ private:
bool filterOutTouchEvent(QEvent *e); bool filterOutTouchEvent(QEvent *e);
void touchScrollTimer(); void touchScrollTimer();
bool touchScroll(const QPoint &delta); void touchScrollUpdated();
void touchScrollUpdated(const QPoint &screenPos); void sendWheelEvent(Qt::ScrollPhase phase, QPoint delta = {});
void touchResetSpeed(); void touchResetSpeed();
void touchUpdateSpeed(); void touchUpdateSpeed();