[pim/mimetreeparser] src/quick: Add basic wheel interceptor

Claudio Cambra <[email protected]>
Newsgroups gmane.comp.kde.cvs
Message-ID <[email protected]>
Git commit 8d2b3512eb2e5b9276b0f3f760274f5fa9abc912 by Claudio Cambra.
Committed on 16/08/2026 at 16:51.
Pushed by clau-cambra into branch 'master'.

Add basic wheel interceptor

a

M  +4    -0    src/quick/CMakeLists.txt
A  +88   -0    src/quick/wheelinterceptor.cpp     [License: LGPL(v2.1+)]
A  +35   -0    src/quick/wheelinterceptor.h     [License: LGPL(v2.1+)]

https://invent.kde.org/pim/mimetreeparser/-/commit/8d2b3512eb2e5b9276b0f3f760274f5fa9abc912

diff --git a/src/quick/CMakeLists.txt b/src/quick/CMakeLists.txt
index 0c8ae6e..86062a1 100644
--- a/src/quick/CMakeLists.txt
+++ b/src/quick/CMakeLists.txt
@@ -16,12 +16,16 @@ target_sources(
         itinerarymodel.cpp
         itinerarymodel.h
         types.h
+        wheelinterceptor.h
+        wheelinterceptor.cpp
 )
 
 target_link_libraries(
     mimetreeparser_plugin
     PRIVATE
         Qt::Qml
+        Qt::Quick
+        Qt::Gui
         ${DBUS_LIB}
         KPim6::MimeTreeParserCore
         KF6::KIOGui
diff --git a/src/quick/wheelinterceptor.cpp b/src/quick/wheelinterceptor.cpp
new file mode 100644
index 0000000..8be10fb
--- /dev/null
+++ b/src/quick/wheelinterceptor.cpp
@@ -0,0 +1,88 @@
+// SPDX-FileCopyrightText: 2025 Claudio Cambra <[email protected]>
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#include "wheelinterceptor.h"
+
+#include <QCoreApplication>
+#include <QGuiApplication>
+#include <QStyleHints>
+#include <QWheelEvent>
+
+WheelInterceptor::WheelInterceptor(QObject *parent)
+    : QObject(parent)
+{
+}
+
+QQuickItem *WheelInterceptor::source() const
+{
+    return m_source;
+}
+
+void WheelInterceptor::setSource(QQuickItem *source)
+{
+    if (m_source == source) {
+        return;
+    }
+    if (m_source) {
+        QCoreApplication::instance()->removeEventFilter(this);
+    }
+    m_source = source;
+    if (m_source) {
+        QCoreApplication::instance()->installEventFilter(this);
+    }
+    Q_EMIT sourceChanged();
+}
+
+QQuickItem *WheelInterceptor::target() const
+{
+    return m_target;
+}
+
+void WheelInterceptor::setTarget(QQuickItem *target)
+{
+    if (m_target == target) {
+        return;
+    }
+    m_target = target;
+    Q_EMIT targetChanged();
+}
+
+static QQuickItem *findTopmostFlickable(QQuickItem *item)
+{
+    QQuickItem *topmost = nullptr;
+    auto current = item;
+    while (current) {
+        if (current->inherits("QQuickFlickable")) {
+            topmost = current;
+        }
+        current = current->parentItem();
+    }
+    return topmost;
+}
+
+bool WheelInterceptor::eventFilter(QObject *obj, QEvent *event)
+{
+    Q_UNUSED(obj);
+    if (event->type() == QEvent::Wheel && m_source && m_target) {
+        auto wheelEvent = static_cast<QWheelEvent *>(event);
+        const auto localPos = m_source->mapFromGlobal(wheelEvent->globalPosition().toPoint());
+        if (m_source->contains(localPos)) {
+            auto flickable = findTopmostFlickable(m_source);
+            if (!flickable) {
+                flickable = findTopmostFlickable(m_target);
+            }
+            if (flickable) {
+                const auto viewH = flickable->height();
+                const auto contentH = flickable->property("contentHeight").toReal();
+                const auto currentY = flickable->property("contentY").toReal();
+                const auto maxScroll = qMax(0.0, contentH - viewH);
+                const auto delta = wheelEvent->angleDelta().y();
+                const auto scrollLines = QGuiApplication::styleHints()->wheelScrollLines();
+                const auto pixels = -(delta / 120.0) * scrollLines * 20.0;
+                flickable->setProperty("contentY", qBound(0.0, currentY + pixels, maxScroll));
+                return true;
+            }
+        }
+    }
+    return false;
+}
diff --git a/src/quick/wheelinterceptor.h b/src/quick/wheelinterceptor.h
new file mode 100644
index 0000000..fa9006d
--- /dev/null
+++ b/src/quick/wheelinterceptor.h
@@ -0,0 +1,35 @@
+// SPDX-FileCopyrightText: 2025 Claudio Cambra <[email protected]>
+// SPDX-License-Identifier: LGPL-2.1-or-later
+
+#pragma once
+
+#include <QObject>
+#include <QQuickItem>
+
+class WheelInterceptor : public QObject
+{
+    Q_OBJECT
+    QML_ELEMENT
+    Q_PROPERTY(QQuickItem *source READ source WRITE setSource NOTIFY sourceChanged)
+    Q_PROPERTY(QQuickItem *target READ target WRITE setTarget NOTIFY targetChanged)
+
+public:
+    explicit WheelInterceptor(QObject *parent = nullptr);
+
+    QQuickItem *source() const;
+    void setSource(QQuickItem *source);
+
+    QQuickItem *target() const;
+    void setTarget(QQuickItem *target);
+
+protected:
+    bool eventFilter(QObject *obj, QEvent *event) override;
+
+Q_SIGNALS:
+    void sourceChanged();
+    void targetChanged();
+
+private:
+    QQuickItem *m_source = nullptr;
+    QQuickItem *m_target = nullptr;
+};
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.