From 8ce73323b52ac9b3d7a73e59080b879989c5b077 Mon Sep 17 00:00:00 2001 From: Robert Griebl Date: Wed, 21 Apr 2010 19:48:00 +0200 Subject: forgot to add the webview scroller --- testapp/qwebviewkineticscroller.cpp | 312 ++++++++++++++++++++++++++++++++++++ testapp/qwebviewkineticscroller.h | 89 ++++++++++ 2 files changed, 401 insertions(+) create mode 100644 testapp/qwebviewkineticscroller.cpp create mode 100644 testapp/qwebviewkineticscroller.h diff --git a/testapp/qwebviewkineticscroller.cpp b/testapp/qwebviewkineticscroller.cpp new file mode 100644 index 0000000..3d3790b --- /dev/null +++ b/testapp/qwebviewkineticscroller.cpp @@ -0,0 +1,312 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if QT_VERSION < 0x040700 +# include +#else +# include +#endif + +#include + +QT_BEGIN_NAMESPACE + +bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event); + +class QWebViewKineticScrollerPrivate +{ +public: + QWebViewKineticScroller *q_ptr; + + QWebView *web; + bool ignoreEvents; + bool touchActive; + bool pressed; + QPointF fractionalPosition; + QPointer scrollFrame; + Qt::ScrollBarPolicy oldHorizontalSBP; + Qt::ScrollBarPolicy oldVerticalSBP; + +#if QT_VERSION < 0x040700 + QTime timer; +#else + QElapsedTimer timer; +#endif + + QWebViewKineticScrollerPrivate() + : q_ptr(0) + , web(0) + , ignoreEvents(false) + , touchActive(false) + , pressed(false) + {} + + void init() + { + timer.start(); + } + + void sendEvent(QWidget *w, QEvent *e) + { + ignoreEvents = true; + qt_sendSpontaneousEvent(w, e); + ignoreEvents = false; + } + + QWebFrame *currentFrame() const; + QWebFrame *scrollingFrameAt(const QPointF &pos) const; +}; + +/*! + * The QWebViewKineticScroller class implements the QKineticScroller for the QWebView + */ +QWebViewKineticScroller::QWebViewKineticScroller() + : QObject() + , QKineticScroller() + , d_ptr(new QWebViewKineticScrollerPrivate()) +{ + Q_D(QWebViewKineticScroller); + d->q_ptr = this; + d->init(); +} + +/*! + Destroys the scroller. +*/ +QWebViewKineticScroller::~QWebViewKineticScroller() +{ } + +void QWebViewKineticScroller::setWidget(QWebView *widget) +{ + Q_D(QWebViewKineticScroller); + + if (d->web) { + d->web->removeEventFilter(this); + d->web->setAttribute(Qt::WA_AcceptTouchEvents, false); + + QWebFrame *mainFrame = d->web->page()->mainFrame(); + mainFrame->setScrollBarPolicy(Qt::Vertical, d->oldVerticalSBP); + mainFrame->setScrollBarPolicy(Qt::Horizontal, d->oldHorizontalSBP); + } + + d->scrollFrame = 0; + reset(); + d->web = widget; + d->fractionalPosition = QPointF(); + setParent(d->web); + + if (d->web) { + QWebFrame *mainFrame = d->web->page()->mainFrame(); + d->oldVerticalSBP = mainFrame->scrollBarPolicy(Qt::Vertical); + d->oldHorizontalSBP = mainFrame->scrollBarPolicy(Qt::Horizontal); + mainFrame->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAlwaysOff); + mainFrame->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAlwaysOff); + d->web->setAttribute(Qt::WA_AcceptTouchEvents, true); + d->web->installEventFilter(this); + } +} + +bool QWebViewKineticScroller::eventFilter(QObject *o, QEvent *e) +{ + Q_D(QWebViewKineticScroller); + + qint64 timestamp = d->timer.elapsed(); + bool res = false; + + if (d->web && (o == d->web) && !d->ignoreEvents && d->web->isEnabled() && isEnabled()) { + switch (e->type()) { + case QEvent::TouchBegin: + case QEvent::TouchUpdate: + case QEvent::TouchEnd: { + qWarning("TOUCH%s", e->type() == QEvent::TouchBegin ? "BEGIN" : (e->type() == QEvent::TouchEnd ? "END" : "UPDATE")); + Input type = (e->type() == QEvent::TouchBegin) ? InputPress : + ((e->type() == QEvent::TouchEnd) ? InputRelease : InputMove); + QTouchEvent *te = static_cast(e); + int idx = (te->deviceType() == QTouchEvent::TouchScreen) ? 0 : 1; + + if (te->touchPoints().count() == (idx + 1)) { + QPointF p = te->touchPoints().at(idx).pos(); + if (type == InputPress) { + // remember the frame where the button was pressed + QWebFrame *hitFrame = d->scrollingFrameAt(p); + if (hitFrame) + d->scrollFrame = hitFrame; + } + + res = handleInput(type, p, timestamp); + if (type == InputPress) { + d->touchActive = true; + res = true; // we need to swallow this event, since WebKit would reject it otherwise + } else if (type == InputRelease) { + d->touchActive = false; + } + qWarning(" TOUCH%s (%d): %d", type == InputPress ? "BEGIN" : (type == InputRelease ? "END" : "UPDATE"), d->touchActive, res); + } + break; + } + case QEvent::Wheel: + // the two-finger gesture on the Mac is mapped to wheel events by default + qWarning("WHEEL"); + res = d->touchActive; + break; + + case QEvent::MouseButtonPress: + // re-install the event filter so that we get the mouse release before all other filters. + // this is an evil hack, but hard to work around without prioritized event filters. + d->web->removeEventFilter(this); + d->web->installEventFilter(this); + // fall through + + case QEvent::MouseButtonDblClick: + case QEvent::MouseMove: + case QEvent::MouseButtonRelease: + if (!d->touchActive) { + Input type = (e->type() == QEvent::MouseButtonRelease) ? InputRelease : + ((e->type() == QEvent::MouseMove) ? InputMove : InputPress); + QPointF p = static_cast(e)->posF(); + + if (type == InputPress) { + // remember the frame where the button was pressed + QWebFrame *hitFrame = d->scrollingFrameAt(p); + if (hitFrame) + d->scrollFrame = hitFrame; + d->pressed = true; + } else if (type == InputRelease) { + d->pressed = false; + } + + if (type != InputMove || d->pressed) + res = handleInput(type, p, timestamp); + } + break; + + default: + break; + } + } + + if (res) + e->accept(); + return res; +} + + +bool QWebViewKineticScroller::canStartScrollingAt(const QPointF & /*pos*/) const +{ + return true; +} + +void QWebViewKineticScroller::cancelPress(const QPointF & /*pressPos*/) +{ +} + +QWebFrame *QWebViewKineticScrollerPrivate::currentFrame() const +{ + if (web && scrollFrame) + return scrollFrame; + else if (web) + return web->page()->mainFrame(); + else + return 0; +} + +// returns the innermost frame at the given position that can be scrolled +QWebFrame *QWebViewKineticScrollerPrivate::scrollingFrameAt(const QPointF &pos) const +{ + QWebFrame *hitFrame = 0; + if (web) { + QWebFrame *mainFrame = web->page()->mainFrame(); + hitFrame = mainFrame->hitTestContent(pos.toPoint()).frame(); + QSize range = hitFrame->contentsSize() - hitFrame->geometry().size(); + + while (hitFrame && range.width() <= 1 && range.height() <= 1) + hitFrame = hitFrame->parentFrame(); + } + return hitFrame; +} + +QSizeF QWebViewKineticScroller::viewportSize() const +{ + Q_D(const QWebViewKineticScroller); + + return d->web ? d->web->page()->viewportSize() : QSize(); +} + +QPointF QWebViewKineticScroller::maximumContentPosition() const +{ + Q_D(const QWebViewKineticScroller); + + QWebFrame *frame = d->currentFrame(); + QSize s = frame ? frame->contentsSize() - frame->geometry().size() : QSize(); + return QPointF(qMax(0, s.width()), qMax(0, s.height())); +} + +QPointF QWebViewKineticScroller::contentPosition() const +{ + Q_D(const QWebViewKineticScroller); + + QWebFrame *frame = d->currentFrame(); + return frame ? QPointF(frame->scrollPosition()) + d->fractionalPosition : QPointF(); +} + +void QWebViewKineticScroller::setContentPosition(const QPointF &p, const QPointF & /*overshoot*/) +{ + Q_D(QWebViewKineticScroller); + + QWebFrame *frame = d->currentFrame(); + if (frame) { + QPoint pint(int(p.x()), int(p.y())); + frame->setScrollPosition(pint); + d->fractionalPosition = p - QPointF(pint); + } +} + +QT_END_NAMESPACE diff --git a/testapp/qwebviewkineticscroller.h b/testapp/qwebviewkineticscroller.h new file mode 100644 index 0000000..1de369d --- /dev/null +++ b/testapp/qwebviewkineticscroller.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtGui module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QWEBVIEWKINETICSCROLLER_H +#define QWEBVIEWKINETICSCROLLER_H + +#include +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Gui) + +class QWebViewKineticScrollerPrivate; + +class Q_GUI_EXPORT QWebViewKineticScroller : public QObject, public QKineticScroller +{ + Q_OBJECT +public: + QWebViewKineticScroller(); + // QWebViewKineticScroller(QWebViewKineticScrollerPrivate &dd); + ~QWebViewKineticScroller(); + + void setWidget(QWebView *widget); + + bool eventFilter(QObject *o, QEvent *e); + +protected: + + virtual QSizeF viewportSize() const; + virtual QPointF maximumContentPosition() const; + virtual QPointF contentPosition() const; + virtual void setContentPosition(const QPointF &pos, const QPointF &overshootDelta); + + virtual bool canStartScrollingAt(const QPointF &pos) const; + virtual void cancelPress(const QPointF &pressPos); + + QScopedPointer d_ptr; + +private: + Q_DISABLE_COPY(QWebViewKineticScroller) + Q_DECLARE_PRIVATE(QWebViewKineticScroller) +}; + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QWEBVIEWSCROLLER_H -- cgit v1.2.3