QPlatformIntegration: add new style hint: SetFocusOnTouchRelease

On desktop platforms, widgets have traditionally received
focus on mouse press. On touch platforms (iOS, Android) this
is different, there you need to delay setting the focus
until a touch release (probably to check if the press starts
a flick or tap'n'hold etc).

This patch will add a new style hint SetFocusOnRelease that
can be set by the plugin to control this behavior in Qt.

Change-Id: I2e4d714894e327822c855eb48a3b28e354726e95
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com>
Reviewed-by: Paul Olav Tvete <paul.tvete@digia.com>
bb10
Richard Moe Gustavsen 2013-06-19 11:21:14 +02:00 committed by The Qt Project
parent a3b5947d36
commit 438211ec62
6 changed files with 57 additions and 26 deletions

View File

@ -328,6 +328,8 @@ QVariant QPlatformIntegration::styleHint(StyleHint hint) const
return QVariant(false);
case SynthesizeMouseFromTouchEvents:
return true;
case SetFocusOnTouchRelease:
return QVariant(false);
}
return 0;

View File

@ -141,7 +141,8 @@ public:
StartDragVelocity,
UseRtlExtensions,
SynthesizeMouseFromTouchEvents,
PasswordMaskCharacter
PasswordMaskCharacter,
SetFocusOnTouchRelease
};
virtual QVariant styleHint(StyleHint hint) const;

View File

@ -218,4 +218,15 @@ bool QStyleHints::useRtlExtensions() const
return hint(QPlatformIntegration::UseRtlExtensions).toBool();
}
/*!
Returns \c true if focus objects (line edits etc) should receive
input focus after a touch/mouse release. This is normal behavior on
touch platforms. On desktop platforms, the standard is to set
focus already on touch/mouse press.
*/
bool QStyleHints::setFocusOnTouchRelease() const
{
return hint(QPlatformIntegration::SetFocusOnTouchRelease).toBool();
}
QT_END_NAMESPACE

View File

@ -65,6 +65,7 @@ public:
QChar passwordMaskCharacter() const;
qreal fontSmoothingGamma() const;
bool useRtlExtensions() const;
bool setFocusOnTouchRelease() const;
private:
friend class QGuiApplication;

View File

@ -2929,12 +2929,8 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
QPoint relpos = mouse->pos();
if (e->spontaneous()) {
if (e->type() == QEvent::MouseButtonPress) {
QApplicationPrivate::giveFocusAccordingToFocusPolicy(w,
Qt::ClickFocus,
Qt::MouseFocusReason);
}
if (e->type() != QEvent::MouseMove)
QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, e, relpos);
// ### Qt 5 These dynamic tool tips should be an OPT-IN feature. Some platforms
// like Mac OS X (probably others too), can optimize their views by not
@ -3022,11 +3018,8 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
QPoint relpos = wheel->pos();
bool eventAccepted = wheel->isAccepted();
if (e->spontaneous()) {
QApplicationPrivate::giveFocusAccordingToFocusPolicy(w,
Qt::WheelFocus,
Qt::MouseFocusReason);
}
if (e->spontaneous())
QApplicationPrivate::giveFocusAccordingToFocusPolicy(w, e, relpos);
while (w) {
QWheelEvent we(relpos, wheel->globalPos(), wheel->pixelDelta(), wheel->angleDelta(), wheel->delta(), wheel->orientation(), wheel->buttons(),
@ -3214,6 +3207,11 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
QTouchEvent *touchEvent = static_cast<QTouchEvent *>(e);
const bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents);
if (e->type() != QEvent::TouchUpdate && acceptTouchEvents && e->spontaneous()) {
const QPoint localPos = touchEvent->touchPoints()[0].pos().toPoint();
QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget, e, localPos);
}
touchEvent->setTarget(widget);
touchEvent->setAccepted(acceptTouchEvents);
@ -3231,16 +3229,16 @@ bool QApplication::notify(QObject *receiver, QEvent *e)
QWidget *widget = static_cast<QWidget *>(receiver);
QTouchEvent *touchEvent = static_cast<QTouchEvent *>(e);
bool eventAccepted = touchEvent->isAccepted();
if (widget->testAttribute(Qt::WA_AcceptTouchEvents) && e->spontaneous()) {
// give the widget focus if the focus policy allows it
QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget,
Qt::ClickFocus,
Qt::MouseFocusReason);
bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents);
if (acceptTouchEvents && e->spontaneous()) {
const QPoint localPos = touchEvent->touchPoints()[0].pos().toPoint();
QApplicationPrivate::giveFocusAccordingToFocusPolicy(widget, e, localPos);
}
while (widget) {
// first, try to deliver the touch event
bool acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents);
acceptTouchEvents = widget->testAttribute(Qt::WA_AcceptTouchEvents);
touchEvent->setTarget(widget);
touchEvent->setAccepted(acceptTouchEvents);
QPointer<QWidget> p = widget;
@ -3705,20 +3703,40 @@ bool qt_sendSpontaneousEvent(QObject *receiver, QEvent *event)
return QGuiApplication::sendSpontaneousEvent(receiver, event);
}
void QApplicationPrivate::giveFocusAccordingToFocusPolicy(QWidget *widget,
Qt::FocusPolicy focusPolicy,
Qt::FocusReason focusReason)
void QApplicationPrivate::giveFocusAccordingToFocusPolicy(QWidget *widget, QEvent *event, QPoint localPos)
{
const bool setFocusOnRelease = QGuiApplication::styleHints()->setFocusOnTouchRelease();
Qt::FocusPolicy focusPolicy = Qt::ClickFocus;
switch (event->type()) {
case QEvent::MouseButtonPress:
case QEvent::TouchBegin:
if (setFocusOnRelease)
return;
break;
case QEvent::MouseButtonRelease:
case QEvent::TouchEnd:
if (!setFocusOnRelease)
return;
break;
case QEvent::Wheel:
focusPolicy = Qt::WheelFocus;
break;
default:
return;
}
QWidget *focusWidget = widget;
while (focusWidget) {
if (focusWidget->isEnabled()
&& focusWidget->rect().contains(localPos)
&& QApplicationPrivate::shouldSetFocus(focusWidget, focusPolicy)) {
focusWidget->setFocus(focusReason);
focusWidget->setFocus(Qt::MouseFocusReason);
break;
}
if (focusWidget->isWindow())
break;
localPos += focusWidget->pos();
focusWidget = focusWidget->parentWidget();
}
}

View File

@ -294,9 +294,7 @@ public:
private:
static QApplicationPrivate *self;
static void giveFocusAccordingToFocusPolicy(QWidget *w,
Qt::FocusPolicy focusPolicy,
Qt::FocusReason focusReason);
static void giveFocusAccordingToFocusPolicy(QWidget *w, QEvent *event, QPoint localPos);
static bool shouldSetFocus(QWidget *w, Qt::FocusPolicy policy);