diff options
author | Andras Becsi <andras.becsi@theqtcompany.com> | 2015-07-21 16:50:26 +0200 |
---|---|---|
committer | Andras Becsi <andras.becsi@theqtcompany.com> | 2015-08-12 17:22:02 +0200 |
commit | f8116095536387c73cce3a0397e16662b42103e6 (patch) | |
tree | 26592871d76d5b552efb2647e4ac221607e7fadd /src | |
parent | 5b72783f06c50ffdfa4c6b5b808253245db89a1f (diff) |
Add TouchTracker and hide the URL bar when scrolling
The tracker makes it possible to hide the URL bar when scrolling
down the page and show it when scrolling up.
The tracker installs an event filter on the RWHVDelegate by
finding it when a touch event arrives.
Diffstat (limited to 'src')
-rw-r--r-- | src/main.cpp | 3 | ||||
-rw-r--r-- | src/qml/BrowserWindow.qml | 51 | ||||
-rw-r--r-- | src/qml/PageView.qml | 26 | ||||
-rw-r--r-- | src/src.pro | 6 | ||||
-rw-r--r-- | src/touchmockingapplication.cpp | 29 | ||||
-rw-r--r-- | src/touchtracker.cpp | 124 | ||||
-rw-r--r-- | src/touchtracker.h | 57 | ||||
-rw-r--r-- | src/utils.h | 29 |
8 files changed, 290 insertions, 35 deletions
diff --git a/src/main.cpp b/src/main.cpp index 339847b..f6645a2 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -43,6 +43,7 @@ #include "touchmockingapplication.h" #include "utils.h" +#include "touchtracker.h" int main(int argc, char **argv) { @@ -67,6 +68,8 @@ int main(int argc, char **argv) #endif QtWebEngine::initialize(); + qmlRegisterType<TouchTracker>("io.qt.browser", 1, 0, "TouchTracker"); + BrowserWindow window; QObject::connect(window.rootContext()->engine(), SIGNAL(quit()), &app, SLOT(quit())); diff --git a/src/qml/BrowserWindow.qml b/src/qml/BrowserWindow.qml index 6fedbc1..0de9d5a 100644 --- a/src/qml/BrowserWindow.qml +++ b/src/qml/BrowserWindow.qml @@ -63,6 +63,11 @@ Item { property string uiSelectionColor: "#fad84a" property int animationDuration: 200 + property int velocityThreshold: 500 + property int velocityY: 0 + property real touchY: 0 + property real touchReference: 0 + property bool touchGesture: false width: 1024 height: 600 @@ -128,7 +133,7 @@ Item { anchors { left: parent.left right: parent.right - top: parent.top + top: navigation.top } visible: opacity != 0.0 @@ -200,8 +205,50 @@ Item { } NavigationBar { id: navigation + + Behavior on y { + NumberAnimation { duration: animationDuration } + } + + y: { + var diff = touchReference - touchY + + if (velocityY > velocityThreshold) { + if (diff > 0) + return -toolBarHeight + else + return 0 + } + + if (!touchGesture || diff == 0) { + if (y < -toolBarHeight / 2) + return -toolBarHeight + else + return 0 + } + + if (diff > toolBarHeight) + return -toolBarHeight + + if (diff > 0) { + if (y == -toolBarHeight) + return -toolBarHeight + return -diff + } + + // diff < 0 + + if (y == 0) + return 0 + + diff = Math.abs(diff) + if (diff >= toolBarHeight) + return 0 + + return -toolBarHeight + diff + } + anchors { - top: parent.top left: parent.left right: parent.right } diff --git a/src/qml/PageView.qml b/src/qml/PageView.qml index a13e220..943ae01 100644 --- a/src/qml/PageView.qml +++ b/src/qml/PageView.qml @@ -35,7 +35,7 @@ ** ****************************************************************************/ -import QtQuick 2.0 +import QtQuick 2.5 import QtWebEngine 1.3 import QtWebEngine.experimental 1.0 import QtQuick.Controls 1.5 @@ -43,6 +43,8 @@ import QtQuick.Controls.Styles 1.4 import QtQuick.Layouts 1.3 import QtGraphicalEffects 1.0 +import io.qt.browser 1.0 + Rectangle { id: root @@ -124,7 +126,7 @@ Rectangle { return tabItem.image.url = webEngineView.url - blur.grabToImage(function(result) { + webEngineView.grabToImage(function(result) { tabItem.image.snapshot = result; console.log("takeSnapshot("+result.url+")") }); @@ -194,11 +196,23 @@ Rectangle { radius: desaturate.desaturation * 25 } - MouseArea { - anchors.fill: parent - enabled: !root.interactive + TouchTracker { + id: tracker - onWheel: wheel.accepted = true + target: webEngineView + anchors.fill: parent + onTouchYChanged: browserWindow.touchY = tracker.touchY + onYVelocityChanged: browserWindow.velocityY = yVelocity + onTouchBegin: { + browserWindow.touchY = tracker.touchY + browserWindow.velocityY = yVelocity + browserWindow.touchReference = tracker.touchY + browserWindow.touchGesture = true + } + onTouchEnd: { + browserWindow.velocityY = yVelocity + browserWindow.touchGesture = false + } } Rectangle { diff --git a/src/src.pro b/src/src.pro index 30e6ce9..d97d37b 100644 --- a/src/src.pro +++ b/src/src.pro @@ -6,11 +6,13 @@ CONFIG -= app_bundle SOURCES = main.cpp \ touchmockingapplication.cpp \ - browserwindow.cpp + browserwindow.cpp \ + touchtracker.cpp HEADERS = utils.h \ touchmockingapplication.h \ - browserwindow.h + browserwindow.h \ + touchtracker.h OTHER_FILES = \ qml/assets/UIButton.qml \ diff --git a/src/touchmockingapplication.cpp b/src/touchmockingapplication.cpp index 4b8da4e..d57c570 100644 --- a/src/touchmockingapplication.cpp +++ b/src/touchmockingapplication.cpp @@ -44,6 +44,10 @@ #include <QMouseEvent> #include <QTouchEvent> +#include "utils.h" + +using namespace utils; + static inline QRectF touchRectForPosition(QPointF centerPoint) { QRectF touchRect(0, 0, 40, 40); @@ -51,31 +55,6 @@ static inline QRectF touchRectForPosition(QPointF centerPoint) return touchRect; } -static inline bool isTouchEvent(const QEvent* event) -{ - switch (event->type()) { - case QEvent::TouchBegin: - case QEvent::TouchUpdate: - case QEvent::TouchEnd: - return true; - default: - return false; - } -} - -static inline bool isMouseEvent(const QEvent* event) -{ - switch (event->type()) { - case QEvent::MouseButtonPress: - case QEvent::MouseMove: - case QEvent::MouseButtonRelease: - case QEvent::MouseButtonDblClick: - return true; - default: - return false; - } -} - TouchMockingApplication::TouchMockingApplication(int& argc, char** argv) : QGuiApplication(argc, argv) , m_realTouchEventReceived(false) diff --git a/src/touchtracker.cpp b/src/touchtracker.cpp new file mode 100644 index 0000000..11cbb6e --- /dev/null +++ b/src/touchtracker.cpp @@ -0,0 +1,124 @@ +#include "touchtracker.h" + +#include <QDateTime> + +#include "utils.h" + +using namespace utils; + +TouchTracker::TouchTracker(QQuickItem *parent) + : QQuickItem(parent) + , m_blockEvents(false) + , m_target(0) + , m_delegate(0) +{ + m_startPoint.ts = 0; + m_currentPoint.ts = 0; +} + +QQuickItem *TouchTracker::target() const +{ + return m_target; +} + +void TouchTracker::setTarget(QQuickItem * target) +{ + m_target = target; + emit targetChanged(); +} + +int TouchTracker::xVelocity() const +{ + qreal pos = qAbs(m_startPoint.x() - m_currentPoint.x()); + qreal time = qAbs(m_startPoint.ts - m_currentPoint.ts); + return pos / time * 1000; +} + +int TouchTracker::yVelocity() const +{ + qreal pos = qAbs(m_startPoint.y() - m_currentPoint.y()); + qreal time = qAbs(m_startPoint.ts - m_currentPoint.ts); + return pos / time * 1000; +} + + +qreal TouchTracker::touchX() const +{ + return m_currentPoint.x(); +} + +qreal TouchTracker::touchY() const +{ + return m_currentPoint.y(); +} + +bool TouchTracker::blockEvents() const +{ + return m_blockEvents; +} + +void TouchTracker::setBlockEvents(bool shouldBlock) +{ + if (m_blockEvents == shouldBlock) + return; + m_blockEvents = shouldBlock; + emit blockEventsChanged(); +} + +bool TouchTracker::eventFilter(QObject *obj, QEvent *event) +{ + if (obj != m_delegate) + return QQuickItem::eventFilter(obj, event); + + if (event->type() == QEvent::Wheel) + return m_blockEvents; + + if (!isTouchEvent(event)) + return QQuickItem::eventFilter(obj, event); + + const QTouchEvent *touch = static_cast<QTouchEvent*>(event); + const QList<QTouchEvent::TouchPoint> &points = touch->touchPoints(); + m_currentPoint.pos = m_target->mapToScene(points.at(0).pos()); + m_currentPoint.ts = QDateTime::currentMSecsSinceEpoch(); + + emit touchChanged(); + emit velocityChanged(); + + if (event->type() == QEvent::TouchEnd) + emit touchEnd(); + + return m_blockEvents; +} + +void TouchTracker::touchEvent(QTouchEvent * event) +{ + if (!m_target) { + if (!m_blockEvents) + QQuickItem::touchEvent(event); + + return; + } + + event->setAccepted(false); + + const QList<QTouchEvent::TouchPoint> &points = event->touchPoints(); + m_currentPoint.pos = m_target->mapToScene(points.at(0).pos()); + m_currentPoint.ts = QDateTime::currentMSecsSinceEpoch(); + + if (event->type() == QEvent::TouchBegin) { + m_startPoint = m_currentPoint; + emit touchBegin(); + } + + emit touchChanged(); + + // We have to find the delegate to be able to filter + // events from the WebEngineView. + // This is a hack and should preferably be made easier + // with the API in some way. + QQuickItem *child = m_target->childAt(m_currentPoint.x(), m_currentPoint.y()); + if (child && m_delegate != child) { + child->installEventFilter(this); + m_delegate = child; + } +} diff --git a/src/touchtracker.h b/src/touchtracker.h new file mode 100644 index 0000000..9aa555a --- /dev/null +++ b/src/touchtracker.h @@ -0,0 +1,57 @@ +#ifndef TOUCHTRACKER_H +#define TOUCHTRACKER_H + +#include <QObject> +#include <QQuickItem> + +class TouchTracker : public QQuickItem +{ + Q_OBJECT + Q_PROPERTY(qreal touchX READ touchX NOTIFY touchChanged) + Q_PROPERTY(qreal touchY READ touchY NOTIFY touchChanged) + Q_PROPERTY(int xVelocity READ xVelocity NOTIFY velocityChanged) + Q_PROPERTY(int yVelocity READ yVelocity NOTIFY velocityChanged) + Q_PROPERTY(bool blockEvents READ blockEvents WRITE setBlockEvents NOTIFY blockEventsChanged) + Q_PROPERTY(QQuickItem* target READ target WRITE setTarget NOTIFY targetChanged) + + struct PositionInfo + { + QPointF pos; + qint64 ts; + qreal x() const { return pos.x(); } + qreal y() const { return pos.y(); } + }; + +public: + TouchTracker(QQuickItem *parent = 0); + + qreal touchX() const; + qreal touchY() const; + int xVelocity() const; + int yVelocity() const; + QQuickItem* target() const; + bool blockEvents() const; + void setBlockEvents(bool shouldBlock); + void setTarget(QQuickItem * target); + +signals: + void touchChanged(); + void blockEventsChanged(); + void targetChanged(); + void touchBegin(); + void touchEnd(); + void velocityChanged(); + +protected: + bool eventFilter(QObject *obj, QEvent *event); + void touchEvent(QTouchEvent *event) override; + +private: + bool m_blockEvents; + PositionInfo m_startPoint; + PositionInfo m_currentPoint; + QQuickItem *m_target; + QQuickItem *m_delegate; +}; + +#endif // TOUCHTRACKER_H diff --git a/src/utils.h b/src/utils.h index 8ea1aea..45ba2ad 100644 --- a/src/utils.h +++ b/src/utils.h @@ -38,9 +38,38 @@ #ifndef UTILS_H #define UTILS_H +#include <QtCore/QEvent> #include <QtCore/QFileInfo> #include <QtCore/QUrl> +namespace utils { +inline bool isTouchEvent(const QEvent* event) +{ + switch (event->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: + return true; + default: + return false; + } +} + +inline bool isMouseEvent(const QEvent* event) +{ + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + case QEvent::MouseButtonDblClick: + return true; + default: + return false; + } +} + +} + class Utils : public QObject { Q_OBJECT |