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

View file

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