Allow custom touch event processing in scroll area.

This commit is contained in:
John Preston 2023-06-27 21:25:16 +04:00
parent 8908c9b5c0
commit 6fe9e08386
2 changed files with 47 additions and 27 deletions

View file

@ -475,32 +475,27 @@ void ScrollArea::touchResetSpeed() {
_touchPrevPosValid = false; _touchPrevPosValid = false;
} }
bool ScrollArea::eventFilter(QObject *obj, QEvent *e) { bool ScrollArea::eventHook(QEvent *e) {
bool res = QScrollArea::eventFilter(obj, e); const auto was = (e->type() == QEvent::LayoutRequest)
if (e->type() == QEvent::TouchBegin || e->type() == QEvent::TouchUpdate || e->type() == QEvent::TouchEnd || e->type() == QEvent::TouchCancel) { ? verticalScrollBar()->minimum()
QTouchEvent *ev = static_cast<QTouchEvent*>(e); : 0;
if (_touchEnabled && ev->device()->type() == base::TouchDevice::TouchScreen) { const auto result = RpWidgetBase<QScrollArea>::eventHook(e);
if (obj == widget()) { if (was) {
touchEvent(ev); // Because LayoutRequest resets custom-set minimum allowed value.
return true; verticalScrollBar()->setMinimum(was);
}
}
} }
return res; return result;
}
bool ScrollArea::eventFilter(QObject *obj, QEvent *e) {
const auto result = QScrollArea::eventFilter(obj, e);
return (obj == widget() && filterOutTouchEvent(e)) || result;
} }
bool ScrollArea::viewportEvent(QEvent *e) { bool ScrollArea::viewportEvent(QEvent *e) {
const auto type = e->type(); if (filterOutTouchEvent(e)) {
if (type == QEvent::TouchBegin return true;
|| type == QEvent::TouchUpdate } else if (e->type() == QEvent::Wheel) {
|| type == QEvent::TouchEnd
|| type == QEvent::TouchCancel) {
QTouchEvent *ev = static_cast<QTouchEvent*>(e);
if (_touchEnabled && ev->device()->type() == base::TouchDevice::TouchScreen) {
touchEvent(ev);
return true;
}
} else if (type == QEvent::Wheel) {
if (_customWheelProcess if (_customWheelProcess
&& _customWheelProcess(static_cast<QWheelEvent*>(e))) { && _customWheelProcess(static_cast<QWheelEvent*>(e))) {
return true; return true;
@ -509,6 +504,24 @@ bool ScrollArea::viewportEvent(QEvent *e) {
return QScrollArea::viewportEvent(e); return QScrollArea::viewportEvent(e);
} }
bool ScrollArea::filterOutTouchEvent(QEvent *e) {
const auto type = e->type();
if (type == QEvent::TouchBegin
|| type == QEvent::TouchUpdate
|| type == QEvent::TouchEnd
|| type == QEvent::TouchCancel) {
const auto ev = static_cast<QTouchEvent*>(e);
if (_customTouchProcess && _customTouchProcess(ev)) {
return true;
} else if (_touchEnabled
&& ev->device()->type() == base::TouchDevice::TouchScreen) {
touchEvent(ev);
return true;
}
}
return false;
}
void ScrollArea::touchEvent(QTouchEvent *e) { void ScrollArea::touchEvent(QTouchEvent *e) {
if (!e->touchPoints().isEmpty()) { if (!e->touchPoints().isEmpty()) {
_touchPrevPos = _touchPos; _touchPrevPos = _touchPos;
@ -624,9 +637,12 @@ void ScrollArea::scrollContentsBy(int dx, int dy) {
} }
bool ScrollArea::touchScroll(const QPoint &delta) { bool ScrollArea::touchScroll(const QPoint &delta) {
int32 scTop = scrollTop(), scMax = scrollTopMax(), scNew = std::clamp(scTop - delta.y(), 0, scMax); const auto scTop = scrollTop();
if (scNew == scTop) return false; const auto scMax = scrollTopMax();
const auto scNew = std::clamp(scTop - delta.y(), 0, scMax);
if (scNew == scTop) {
return false;
}
scrollToY(scNew); scrollToY(scNew);
return true; return true;
} }

View file

@ -175,12 +175,16 @@ public:
void setCustomWheelProcess(Fn<bool(not_null<QWheelEvent*>)> process) { void setCustomWheelProcess(Fn<bool(not_null<QWheelEvent*>)> process) {
_customWheelProcess = std::move(process); _customWheelProcess = std::move(process);
} }
void setCustomTouchProcess(Fn<bool(not_null<QTouchEvent*>)> process) {
_customTouchProcess = std::move(process);
}
[[nodiscard]] rpl::producer<> scrolls() const; [[nodiscard]] rpl::producer<> scrolls() const;
[[nodiscard]] rpl::producer<> innerResizes() const; [[nodiscard]] rpl::producer<> innerResizes() const;
[[nodiscard]] rpl::producer<> geometryChanged() const; [[nodiscard]] rpl::producer<> geometryChanged() const;
protected: protected:
bool eventHook(QEvent *e) override;
bool eventFilter(QObject *obj, QEvent *e) override; bool eventFilter(QObject *obj, QEvent *e) override;
void resizeEvent(QResizeEvent *e) override; void resizeEvent(QResizeEvent *e) override;
@ -197,8 +201,7 @@ private:
void doSetOwnedWidget(object_ptr<QWidget> widget); void doSetOwnedWidget(object_ptr<QWidget> widget);
object_ptr<QWidget> doTakeWidget(); object_ptr<QWidget> doTakeWidget();
void setWidget(QWidget *widget); bool filterOutTouchEvent(QEvent *e);
void touchScrollTimer(); void touchScrollTimer();
bool touchScroll(const QPoint &delta); bool touchScroll(const QPoint &delta);
void touchScrollUpdated(const QPoint &screenPos); void touchScrollUpdated(const QPoint &screenPos);
@ -232,6 +235,7 @@ private:
base::Timer _touchScrollTimer; base::Timer _touchScrollTimer;
Fn<bool(not_null<QWheelEvent*>)> _customWheelProcess; Fn<bool(not_null<QWheelEvent*>)> _customWheelProcess;
Fn<bool(not_null<QTouchEvent*>)> _customTouchProcess;
bool _widgetAcceptsTouch = false; bool _widgetAcceptsTouch = false;
object_ptr<QWidget> _widget = { nullptr }; object_ptr<QWidget> _widget = { nullptr };