aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@qt.io>2017-04-27 21:51:56 +0300
committerJ-P Nurmi <jpnurmi@qt.io>2017-04-27 21:52:01 +0300
commitea470e8d612e5aa8c12eb3393baf057b8e8149e4 (patch)
treeb5b77618de709c2cd818970b42f138d8e4b7c390
parent806b1f7c4ed218d4df67428277f06bdbb1c71e0e (diff)
parentf9552a96a7c6f8ea58d8ea90cf3027cc0636bf64 (diff)
Merge remote-tracking branch 'origin/5.9' into dev
-rw-r--r--src/imports/controls/material/RoundButton.qml2
-rw-r--r--src/quicktemplates2/qquickcontainer.cpp70
-rw-r--r--src/quicktemplates2/qquickdrawer.cpp362
-rw-r--r--src/quicktemplates2/qquickdrawer_p.h4
-rw-r--r--src/quicktemplates2/qquickdrawer_p_p.h11
-rw-r--r--src/quicktemplates2/qquickoverlay.cpp186
-rw-r--r--src/quicktemplates2/qquickoverlay_p_p.h10
-rw-r--r--src/quicktemplates2/qquickpopup.cpp187
-rw-r--r--src/quicktemplates2/qquickpopup_p_p.h13
-rw-r--r--src/quicktemplates2/qquickrangeslider.cpp20
-rw-r--r--src/quicktemplates2/qquickspinbox.cpp10
-rw-r--r--src/quicktemplates2/qquickspinbox_p.h1
-rw-r--r--tests/auto/controls/data/tst_container.qml36
-rw-r--r--tests/auto/controls/data/tst_dial.qml13
-rw-r--r--tests/auto/controls/data/tst_dialog.qml24
-rw-r--r--tests/auto/controls/data/tst_popup.qml7
-rw-r--r--tests/auto/controls/data/tst_rangeslider.qml27
-rw-r--r--tests/auto/controls/data/tst_slider.qml13
-rw-r--r--tests/auto/controls/data/tst_spinbox.qml11
-rw-r--r--tests/auto/drawer/tst_drawer.cpp53
-rw-r--r--tests/auto/focus/data/keyNavigation.qml1
-rw-r--r--tests/auto/popup/tst_popup.cpp32
22 files changed, 700 insertions, 393 deletions
diff --git a/src/imports/controls/material/RoundButton.qml b/src/imports/controls/material/RoundButton.qml
index c8d4f9a3..ac5949d9 100644
--- a/src/imports/controls/material/RoundButton.qml
+++ b/src/imports/controls/material/RoundButton.qml
@@ -59,7 +59,7 @@ T.RoundButton {
icon.color: enabled ? undefined : Material.hintTextColor
Material.elevation: flat ? control.down || control.hovered ? 2 : 0
- : control.down ? 8 : 2
+ : control.down ? 12 : 6
Material.background: flat ? "transparent" : undefined
contentItem: IconLabel {
diff --git a/src/quicktemplates2/qquickcontainer.cpp b/src/quicktemplates2/qquickcontainer.cpp
index 6777fa5d..2bc37e9c 100644
--- a/src/quicktemplates2/qquickcontainer.cpp
+++ b/src/quicktemplates2/qquickcontainer.cpp
@@ -96,6 +96,54 @@ QT_BEGIN_NAMESPACE
}
\endcode
+ \section2 Managing the Current Index
+
+ When using multiple containers, such as \l TabBar and \l SwipeView, together,
+ their \l currentIndex properties can be bound to each other to keep them in
+ sync. When the user interacts with either container, its current index changes
+ automatically propagate to the other container.
+
+ Notice, however, that assigning a \c currentIndex value in JavaScript removes
+ the respective binding. In order to retain the bindings, use the following
+ methods to alter the current index:
+
+ \list
+ \li \l incrementCurrentIndex()
+ \li \l decrementCurrentIndex()
+ \li \l setCurrentIndex(int index)
+ \endlist
+
+ \code
+ TabBar {
+ id: tabBar
+ currentIndex: swipeView.currentIndex
+ }
+
+ SwipeView {
+ id: swipeView
+ currentIndex: tabBar.currentIndex
+ }
+
+ Button {
+ text: qsTr("Home")
+ onClicked: swipeView.setCurrentIndex(0)
+ enabled: swipeView.currentIndex != 0
+ }
+
+ Button {
+ text: qsTr("Previous")
+ onClicked: swipeView.decrementCurrentIndex()
+ enabled: swipeView.currentIndex > 0
+ }
+
+ Button {
+ text: qsTr("Next")
+ onClicked: swipeView.incrementCurrentIndex()
+ enabled: swipeView.currentIndex < swipeView.count - 1
+ }
+ \endcode
+
+
\section2 Implementing Containers
Container does not provide any default visualization. It is used to implement
@@ -551,7 +599,7 @@ QQmlListProperty<QQuickItem> QQuickContainer::contentChildren()
This property holds the index of the current item.
- \sa currentItem, incrementCurrentIndex(), decrementCurrentIndex()
+ \sa currentItem, {Managing the Current Index}
*/
int QQuickContainer::currentIndex() const
{
@@ -559,6 +607,16 @@ int QQuickContainer::currentIndex() const
return d->currentIndex;
}
+/*!
+ \qmlmethod void QtQuick.Controls::Container::setCurrentIndex(int index)
+
+ Sets the current index of the container.
+
+ This method can be called to set a specific current index without breaking
+ existing \c currentIndex bindings.
+
+ \sa currentIndex, {Managing the Current Index}
+*/
void QQuickContainer::setCurrentIndex(int index)
{
Q_D(QQuickContainer);
@@ -576,7 +634,10 @@ void QQuickContainer::setCurrentIndex(int index)
Increments the current index of the container.
- \sa currentIndex
+ This method can be called to alter the current index without breaking
+ existing \c currentIndex bindings.
+
+ \sa currentIndex, {Managing the Current Index}
*/
void QQuickContainer::incrementCurrentIndex()
{
@@ -591,7 +652,10 @@ void QQuickContainer::incrementCurrentIndex()
Decrements the current index of the container.
- \sa currentIndex
+ This method can be called to alter the current index without breaking
+ existing \c currentIndex bindings.
+
+ \sa currentIndex, {Managing the Current Index}
*/
void QQuickContainer::decrementCurrentIndex()
{
diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp
index 0c53093b..76a09d11 100644
--- a/src/quicktemplates2/qquickdrawer.cpp
+++ b/src/quicktemplates2/qquickdrawer.cpp
@@ -234,35 +234,17 @@ void QQuickDrawerPrivate::resizeOverlay()
dimmer->setSize(geometry.size());
}
-static bool mouseDragOverThreshold(QQuickDrawer *drawer, QMouseEvent *event)
+static bool isWithinDragMargin(QQuickDrawer *drawer, const QPointF &pos)
{
switch (drawer->edge()) {
case Qt::LeftEdge:
- return !QQuickWindowPrivate::dragOverThreshold(event->windowPos().x(), Qt::XAxis, event, drawer->dragMargin());
+ return pos.x() <= drawer->dragMargin();
case Qt::RightEdge:
- return !QQuickWindowPrivate::dragOverThreshold(drawer->window()->width() - event->windowPos().x(), Qt::XAxis, event, drawer->dragMargin());
+ return pos.x() >= drawer->window()->width() - drawer->dragMargin();
case Qt::TopEdge:
- return !QQuickWindowPrivate::dragOverThreshold(event->windowPos().y(), Qt::YAxis, event, drawer->dragMargin());
+ return pos.y() <= drawer->dragMargin();
case Qt::BottomEdge:
- return !QQuickWindowPrivate::dragOverThreshold(drawer->window()->height() - event->windowPos().y(), Qt::YAxis, event, drawer->dragMargin());
- default:
- Q_UNREACHABLE();
- break;
- }
- return false;
-}
-
-static bool touchDragOverThreshold(QQuickDrawer *drawer, const QTouchEvent::TouchPoint &point)
-{
- switch (drawer->edge()) {
- case Qt::LeftEdge:
- return !QQuickWindowPrivate::dragOverThreshold(point.scenePos().x(), Qt::XAxis, &point, drawer->dragMargin());
- case Qt::RightEdge:
- return !QQuickWindowPrivate::dragOverThreshold(drawer->window()->width() - point.scenePos().x(), Qt::XAxis, &point, drawer->dragMargin());
- case Qt::TopEdge:
- return !QQuickWindowPrivate::dragOverThreshold(point.scenePos().y(), Qt::YAxis, &point, drawer->dragMargin());
- case Qt::BottomEdge:
- return !QQuickWindowPrivate::dragOverThreshold(drawer->window()->height() - point.scenePos().y(), Qt::YAxis, &point, drawer->dragMargin());
+ return pos.y() >= drawer->window()->height() - drawer->dragMargin();
default:
Q_UNREACHABLE();
break;
@@ -276,33 +258,38 @@ bool QQuickDrawerPrivate::startDrag(QEvent *event)
if (!window || !interactive || dragMargin < 0.0 || qFuzzyIsNull(dragMargin))
return false;
- bool overThreshold = false;
- bool mouse = event->type() == QEvent::MouseButtonPress;
- if (mouse) {
- overThreshold = mouseDragOverThreshold(q, static_cast<QMouseEvent *>(event));
- } else {
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ if (isWithinDragMargin(q, static_cast<QMouseEvent *>(event)->windowPos())) {
+ prepareEnterTransition();
+ reposition();
+ return handleMouseEvent(window->contentItem(), static_cast<QMouseEvent *>(event));
+ }
+ break;
+
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
for (const QTouchEvent::TouchPoint &point : static_cast<QTouchEvent *>(event)->touchPoints()) {
- if (touchDragOverThreshold(q, point)) {
- overThreshold = true;
- break;
+ if (point.state() == Qt::TouchPointPressed && isWithinDragMargin(q, point.scenePos())) {
+ prepareEnterTransition();
+ reposition();
+ return handleTouchEvent(window->contentItem(), static_cast<QTouchEvent *>(event));
}
}
- }
- if (!overThreshold)
- return false;
+ break;
- prepareEnterTransition();
- reposition();
- if (mouse) {
- handleMousePressEvent(window->contentItem(), static_cast<QMouseEvent *>(event));
- return true;
+ default:
+ break;
}
+
return false;
}
-bool QQuickDrawerPrivate::grabMouse(QMouseEvent *event)
+bool QQuickDrawerPrivate::grabMouse(QQuickItem *item, QMouseEvent *event)
{
Q_Q(QQuickDrawer);
+ handleMouseEvent(item, event);
+
if (!window || !interactive || popupItem->keepMouseGrab())
return false;
@@ -328,125 +315,174 @@ bool QQuickDrawerPrivate::grabMouse(QMouseEvent *event)
overThreshold = qAbs(movePoint.y() - q->height()) < dragMargin;
}
+ if (overThreshold) {
+ QQuickItem *grabber = window->mouseGrabberItem();
+ if (!grabber || !grabber->keepMouseGrab()) {
+ popupItem->grabMouse();
+ popupItem->setKeepMouseGrab(true);
+ offset = positionAt(movePoint) - position;
+
+ // don't jump when dragged open
+ if (offset > 0 && position > 0 && !popupItem->contains(popupItem->mapFromScene(movePoint)))
+ offset = 0;
+ }
+ }
+
return overThreshold;
}
-static const qreal openCloseVelocityThreshold = 300;
-
-bool QQuickDrawerPrivate::ungrabMouse(QMouseEvent *event)
+bool QQuickDrawerPrivate::grabTouch(QQuickItem *item, QTouchEvent *event)
{
- bool wasGrabbed = popupItem->keepMouseGrab();
- if (wasGrabbed) {
- const QPointF releasePoint = event->windowPos();
- velocityCalculator.stopMeasuring(releasePoint, event->timestamp());
+ Q_Q(QQuickDrawer);
+ handleTouchEvent(item, event);
- qreal velocity = 0;
- if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
- velocity = velocityCalculator.velocity().x();
- else
- velocity = velocityCalculator.velocity().y();
-
- // the velocity is calculated so that swipes from left to right
- // and top to bottom have positive velocity, and swipes from right
- // to left and bottom to top have negative velocity.
- //
- // - top/left edge: positive velocity opens, negative velocity closes
- // - bottom/right edge: negative velocity opens, positive velocity closes
- //
- // => invert the velocity for bottom and right edges, for the threshold comparison below
- if (edge == Qt::RightEdge || edge == Qt::BottomEdge)
- velocity = -velocity;
-
- if (position > 0.7 || velocity > openCloseVelocityThreshold) {
- transitionManager.transitionEnter();
- } else if (position < 0.3 || velocity < -openCloseVelocityThreshold) {
- transitionManager.transitionExit();
- } else {
- switch (edge) {
- case Qt::LeftEdge:
- if (releasePoint.x() - pressPoint.x() > 0)
- transitionManager.transitionEnter();
- else
- transitionManager.transitionExit();
- break;
- case Qt::RightEdge:
- if (releasePoint.x() - pressPoint.x() < 0)
- transitionManager.transitionEnter();
- else
- transitionManager.transitionExit();
- break;
- case Qt::TopEdge:
- if (releasePoint.y() - pressPoint.y() > 0)
- transitionManager.transitionEnter();
- else
- transitionManager.transitionExit();
- break;
- case Qt::BottomEdge:
- if (releasePoint.y() - pressPoint.y() < 0)
- transitionManager.transitionEnter();
- else
- transitionManager.transitionExit();
- break;
- }
+ if (!window || !interactive || popupItem->keepTouchGrab() || !event->touchPointStates().testFlag(Qt::TouchPointMoved))
+ return false;
+
+ bool overThreshold = false;
+ for (const QTouchEvent::TouchPoint &point : event->touchPoints()) {
+ if (!acceptTouch(point) || point.state() != Qt::TouchPointMoved)
+ continue;
+
+ const QPointF movePoint = point.scenePos();
+
+ // Flickable uses a hard-coded threshold of 15 for flicking, and
+ // QStyleHints::startDragDistance for dragging. Drawer uses a bit
+ // larger threshold to avoid being too eager to steal touch (QTBUG-50045)
+ const int threshold = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5);
+ if (position > 0 || dragMargin > 0) {
+ if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
+ overThreshold = QQuickWindowPrivate::dragOverThreshold(movePoint.x() - pressPoint.x(), Qt::XAxis, &point, threshold);
+ else
+ overThreshold = QQuickWindowPrivate::dragOverThreshold(movePoint.y() - pressPoint.y(), Qt::YAxis, &point, threshold);
+ }
+
+ // Don't be too eager to steal presses outside the drawer (QTBUG-53929)
+ if (overThreshold && qFuzzyCompare(position, qreal(1.0)) && !popupItem->contains(popupItem->mapFromScene(movePoint))) {
+ if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
+ overThreshold = qAbs(movePoint.x() - q->width()) < dragMargin;
+ else
+ overThreshold = qAbs(movePoint.y() - q->height()) < dragMargin;
+ }
+
+ if (overThreshold) {
+ popupItem->setKeepTouchGrab(true);
+ offset = positionAt(movePoint) - position;
+
+ // don't jump when dragged open
+ if (offset > 0 && position > 0 && !popupItem->contains(popupItem->mapFromScene(movePoint)))
+ offset = 0;
}
}
- return wasGrabbed;
+
+ return overThreshold;
}
-bool QQuickDrawerPrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *event)
+static const qreal openCloseVelocityThreshold = 300;
+
+bool QQuickDrawerPrivate::handlePress(QQuickItem *item, const QPointF &point, ulong timestamp)
{
+ if (!QQuickPopupPrivate::handlePress(item, point, timestamp))
+ return false;
+
offset = 0;
- pressPoint = event->windowPos();
- velocityCalculator.startMeasuring(pressPoint, event->timestamp());
-
- // don't block press events
- // a) outside a non-modal drawer,
- // b) to drawer children, or
- // c) outside a modal drawer's background dimming
- event->setAccepted(modal && !popupItem->isAncestorOf(item) && (!dimmer || dimmer->contains(dimmer->mapFromScene(pressPoint))));
- return event->isAccepted();
+ pressPoint = point;
+ velocityCalculator.startMeasuring(point, timestamp);
+
+ return true;
}
-bool QQuickDrawerPrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event)
+bool QQuickDrawerPrivate::handleMove(QQuickItem *item, const QPointF &point, ulong timestamp)
{
Q_Q(QQuickDrawer);
- Q_UNUSED(item);
+ if (!QQuickPopupPrivate::handleMove(item, point, timestamp))
+ return false;
- // Don't react to synthesized mouse move events at INF,INF coordinates.
- // QQuickWindowPrivate::translateTouchToMouse() uses them to clear hover
- // on touch release (QTBUG-55995).
- if (qIsInf(event->screenPos().x()) || qIsInf(event->screenPos().y()))
- return true;
+ // limit/reset the offset to the edge of the drawer when pushed from the outside
+ if (qFuzzyCompare(position, 1.0) && !popupItem->contains(popupItem->mapFromScene(point)))
+ offset = 0;
- const QPointF movePoint = event->windowPos();
+ bool isGrabbed = popupItem->keepMouseGrab() || popupItem->keepTouchGrab();
+ if (isGrabbed)
+ q->setPosition(positionAt(point) - offset);
- if (grabMouse(event)) {
- QQuickItem *grabber = window->mouseGrabberItem();
- if (!grabber || !grabber->keepMouseGrab()) {
- popupItem->grabMouse();
- popupItem->setKeepMouseGrab(true);
- offset = qMin<qreal>(0.0, positionAt(movePoint) - position);
+ return isGrabbed;
+}
+
+bool QQuickDrawerPrivate::handleRelease(QQuickItem *item, const QPointF &point, ulong timestamp)
+{
+ pressPoint = QPointF();
+
+ if (!popupItem->keepMouseGrab() && !popupItem->keepTouchGrab()) {
+ velocityCalculator.reset();
+ return QQuickPopupPrivate::handleRelease(item, point, timestamp);
+ }
+
+ velocityCalculator.stopMeasuring(point, timestamp);
+
+ qreal velocity = 0;
+ if (edge == Qt::LeftEdge || edge == Qt::RightEdge)
+ velocity = velocityCalculator.velocity().x();
+ else
+ velocity = velocityCalculator.velocity().y();
+
+ // the velocity is calculated so that swipes from left to right
+ // and top to bottom have positive velocity, and swipes from right
+ // to left and bottom to top have negative velocity.
+ //
+ // - top/left edge: positive velocity opens, negative velocity closes
+ // - bottom/right edge: negative velocity opens, positive velocity closes
+ //
+ // => invert the velocity for bottom and right edges, for the threshold comparison below
+ if (edge == Qt::RightEdge || edge == Qt::BottomEdge)
+ velocity = -velocity;
+
+ if (position > 0.7 || velocity > openCloseVelocityThreshold) {
+ transitionManager.transitionEnter();
+ } else if (position < 0.3 || velocity < -openCloseVelocityThreshold) {
+ transitionManager.transitionExit();
+ } else {
+ switch (edge) {
+ case Qt::LeftEdge:
+ if (point.x() - pressPoint.x() > 0)
+ transitionManager.transitionEnter();
+ else
+ transitionManager.transitionExit();
+ break;
+ case Qt::RightEdge:
+ if (point.x() - pressPoint.x() < 0)
+ transitionManager.transitionEnter();
+ else
+ transitionManager.transitionExit();
+ break;
+ case Qt::TopEdge:
+ if (point.y() - pressPoint.y() > 0)
+ transitionManager.transitionEnter();
+ else
+ transitionManager.transitionExit();
+ break;
+ case Qt::BottomEdge:
+ if (point.y() - pressPoint.y() < 0)
+ transitionManager.transitionEnter();
+ else
+ transitionManager.transitionExit();
+ break;
}
}
- if (popupItem->keepMouseGrab())
- q->setPosition(positionAt(movePoint) - offset);
- event->accept();
+ bool wasGrabbed = popupItem->keepMouseGrab() || popupItem->keepTouchGrab();
+ popupItem->setKeepMouseGrab(false);
+ popupItem->setKeepTouchGrab(false);
- return popupItem->keepMouseGrab();
+ return wasGrabbed;
}
-bool QQuickDrawerPrivate::handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event)
+void QQuickDrawerPrivate::handleUngrab()
{
- Q_UNUSED(item);
+ QQuickPopupPrivate::handleUngrab();
- const bool wasGrabbed = ungrabMouse(event);
-
- popupItem->setKeepMouseGrab(false);
pressPoint = QPoint();
- event->accept();
-
- return wasGrabbed;
+ velocityCalculator.reset();
}
static QList<QQuickStateAction> prepareTransition(QQuickDrawer *drawer, QQuickTransition *transition, qreal to)
@@ -629,69 +665,43 @@ bool QQuickDrawer::childMouseEventFilter(QQuickItem *child, QEvent *event)
{
Q_D(QQuickDrawer);
switch (event->type()) {
- case QEvent::MouseButtonPress:
- return d->handleMousePressEvent(child, static_cast<QMouseEvent *>(event));
+ case QEvent::TouchUpdate:
+ return d->grabTouch(child, static_cast<QTouchEvent *>(event));
case QEvent::MouseMove:
- return d->handleMouseMoveEvent(child, static_cast<QMouseEvent *>(event));
+ return d->grabMouse(child, static_cast<QMouseEvent *>(event));
+ case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
- return d->handleMouseReleaseEvent(child, static_cast<QMouseEvent *>(event));
+ return d->handleMouseEvent(child, static_cast<QMouseEvent *>(event));
default:
- return false;
+ break;
}
-}
-
-void QQuickDrawer::mousePressEvent(QMouseEvent *event)
-{
- Q_D(QQuickDrawer);
- QQuickPopup::mousePressEvent(event);
- d->handleMousePressEvent(d->popupItem, event);
+ return false;
}
void QQuickDrawer::mouseMoveEvent(QMouseEvent *event)
{
Q_D(QQuickDrawer);
- QQuickPopup::mouseMoveEvent(event);
- d->handleMouseMoveEvent(d->popupItem, event);
-}
-
-void QQuickDrawer::mouseReleaseEvent(QMouseEvent *event)
-{
- Q_D(QQuickDrawer);
- QQuickPopup::mouseReleaseEvent(event);
- d->handleMouseReleaseEvent(d->popupItem, event);
-}
-
-void QQuickDrawer::mouseUngrabEvent()
-{
- Q_D(QQuickDrawer);
- QQuickPopup::mouseUngrabEvent();
- d->pressPoint = QPoint();
- d->velocityCalculator.reset();
+ d->grabMouse(d->popupItem, event);
}
bool QQuickDrawer::overlayEvent(QQuickItem *item, QEvent *event)
{
Q_D(QQuickDrawer);
switch (event->type()) {
- case QEvent::TouchBegin:
case QEvent::TouchUpdate:
- case QEvent::TouchEnd:
- case QEvent::TouchCancel:
- // TODO: QQuickDrawer still relies on synthesized mouse events
- event->ignore();
- return false;
-
- case QEvent::MouseButtonPress:
- d->tryClose(item, event);
- return d->handleMousePressEvent(item, static_cast<QMouseEvent *>(event));
+ return d->grabTouch(item, static_cast<QTouchEvent *>(event));
case QEvent::MouseMove:
- return d->handleMouseMoveEvent(item, static_cast<QMouseEvent *>(event));
- case QEvent::MouseButtonRelease:
- d->tryClose(item, event);
- return d->handleMouseReleaseEvent(item, static_cast<QMouseEvent *>(event));
+ return d->grabMouse(item, static_cast<QMouseEvent *>(event));
default:
- return QQuickPopup::overlayEvent(item, event);
+ break;
}
+ return QQuickPopup::overlayEvent(item, event);
+}
+
+void QQuickDrawer::touchEvent(QTouchEvent *event)
+{
+ Q_D(QQuickDrawer);
+ d->grabTouch(d->popupItem, event);
}
void QQuickDrawer::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
diff --git a/src/quicktemplates2/qquickdrawer_p.h b/src/quicktemplates2/qquickdrawer_p.h
index 68b58362..9ab1c4ef 100644
--- a/src/quicktemplates2/qquickdrawer_p.h
+++ b/src/quicktemplates2/qquickdrawer_p.h
@@ -86,11 +86,9 @@ Q_SIGNALS:
protected:
bool childMouseEventFilter(QQuickItem *child, QEvent *event) override;
- void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
- void mouseReleaseEvent(QMouseEvent *event) override;
- void mouseUngrabEvent() override;
bool overlayEvent(QQuickItem *item, QEvent *event) override;
+ void touchEvent(QTouchEvent *event) override;
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
diff --git a/src/quicktemplates2/qquickdrawer_p_p.h b/src/quicktemplates2/qquickdrawer_p_p.h
index c2c5beaf..dba3032e 100644
--- a/src/quicktemplates2/qquickdrawer_p_p.h
+++ b/src/quicktemplates2/qquickdrawer_p_p.h
@@ -71,12 +71,13 @@ public:
void resizeOverlay() override;
bool startDrag(QEvent *event);
- bool grabMouse(QMouseEvent *event);
- bool ungrabMouse(QMouseEvent *event);
+ bool grabMouse(QQuickItem *item, QMouseEvent *event);
+ bool grabTouch(QQuickItem *item, QTouchEvent *event);
- bool handleMousePressEvent(QQuickItem *item, QMouseEvent *event);
- bool handleMouseMoveEvent(QQuickItem *item, QMouseEvent *event);
- bool handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event);
+ bool handlePress(QQuickItem* item, const QPointF &point, ulong timestamp) override;
+ bool handleMove(QQuickItem* item, const QPointF &point, ulong timestamp) override;
+ bool handleRelease(QQuickItem* item, const QPointF &point, ulong timestamp) override;
+ void handleUngrab() override;
bool prepareEnterTransition() override;
bool prepareExitTransition() override;
diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp
index 58ec5582..308eda86 100644
--- a/src/quicktemplates2/qquickoverlay.cpp
+++ b/src/quicktemplates2/qquickoverlay.cpp
@@ -181,57 +181,136 @@ QQuickOverlayPrivate::QQuickOverlayPrivate()
{
}
-void QQuickOverlayPrivate::handlePress(QEvent *event)
+bool QQuickOverlayPrivate::startDrag(QEvent *event)
+{
+ if (allDrawers.isEmpty())
+ return false;
+
+ const QVector<QQuickDrawer *> drawers = stackingOrderDrawers();
+ for (QQuickDrawer *drawer : drawers) {
+ QQuickDrawerPrivate *p = QQuickDrawerPrivate::get(drawer);
+ if (p->startDrag(event)) {
+ setMouseGrabberPopup(drawer);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool QQuickOverlayPrivate::handlePress(QQuickItem *source, QEvent *event, QQuickPopup *target)
{
Q_Q(QQuickOverlay);
emit q->pressed();
- if (!allDrawers.isEmpty()) {
- // the overlay background was pressed, so there are no modal popups open.
- // test if the press point lands on any drawer's drag margin
-
- const QVector<QQuickDrawer *> drawers = stackingOrderDrawers();
- for (QQuickDrawer *drawer : drawers) {
- QQuickDrawerPrivate *p = QQuickDrawerPrivate::get(drawer);
- if (p->startDrag(event)) {
- setMouseGrabberPopup(drawer);
- return;
- }
+ if (target) {
+ if (target->overlayEvent(source, event)) {
+ setMouseGrabberPopup(target);
+ return true;
}
- }
-
- if (!mouseGrabberPopup) {
- // allow non-modal popups to close themselves
+ return false;
+ } else if (!mouseGrabberPopup) {
+ // allow non-modal popups to close themselves,
+ // and non-dimming modal popups to block the event
const auto popups = stackingOrderPopups();
- for (QQuickPopup *popup : popups)
- popup->overlayEvent(q, event);
+ for (QQuickPopup *popup : popups) {
+ if (popup->overlayEvent(source, event)) {
+ setMouseGrabberPopup(popup);
+ return true;
+ }
+ }
}
event->ignore();
+ return false;
}
-void QQuickOverlayPrivate::handleMove(QEvent *event)
+bool QQuickOverlayPrivate::handleMove(QQuickItem *source, QEvent *event, QQuickPopup *target)
{
- Q_Q(QQuickOverlay);
- if (mouseGrabberPopup)
- mouseGrabberPopup->overlayEvent(q, event);
+ if (target)
+ return target->overlayEvent(source, event);
+ return false;
}
-void QQuickOverlayPrivate::handleRelease(QEvent *event)
+bool QQuickOverlayPrivate::handleRelease(QQuickItem *source, QEvent *event, QQuickPopup *target)
{
Q_Q(QQuickOverlay);
emit q->released();
- if (mouseGrabberPopup) {
- mouseGrabberPopup->overlayEvent(q, event);
+ if (target) {
setMouseGrabberPopup(nullptr);
+ if (target->overlayEvent(source, event)) {
+ setMouseGrabberPopup(nullptr);
+ return true;
+ }
} else {
const auto popups = stackingOrderPopups();
for (QQuickPopup *popup : popups) {
- if (popup->overlayEvent(q, event))
+ if (popup->overlayEvent(source, event))
+ return true;
+ }
+ }
+ return false;
+}
+
+bool QQuickOverlayPrivate::handleMouseEvent(QQuickItem *source, QMouseEvent *event, QQuickPopup *target)
+{
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ if (!target && startDrag(event))
+ return true;
+ return handlePress(source, event, target);
+ case QEvent::MouseMove:
+ return handleMove(source, event, target ? target : mouseGrabberPopup.data());
+ case QEvent::MouseButtonRelease:
+ return handleRelease(source, event, target ? target : mouseGrabberPopup.data());
+ default:
+ break;
+ }
+ return false;
+}
+
+bool QQuickOverlayPrivate::handleTouchEvent(QQuickItem *source, QTouchEvent *event, QQuickPopup *target)
+{
+ bool handled = false;
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ if (!target && startDrag(event))
+ handled = true;
+ else
+ handled = handlePress(source, event, target);
+ break;
+
+ case QEvent::TouchUpdate:
+ for (const QTouchEvent::TouchPoint &point : event->touchPoints()) {
+ switch (point.state()) {
+ case Qt::TouchPointPressed:
+ if (!target && startDrag(event))
+ handled = true;
+ else
+ handled |= handlePress(source, event, target);
+ break;
+ case Qt::TouchPointMoved:
+ handled |= handleMove(source, event, target ? target : mouseGrabberPopup.data());
+ break;
+ case Qt::TouchPointReleased:
+ handled |= handleRelease(source, event, target ? target : mouseGrabberPopup.data());
break;
+ default:
+ break;
+ }
}
+ break;
+
+ case QEvent::TouchEnd:
+ handled = handleRelease(source, event, target ? target : mouseGrabberPopup.data());
+ break;
+
+ default:
+ break;
}
+
+ return handled;
}
void QQuickOverlayPrivate::addPopup(QQuickPopup *popup)
@@ -382,55 +461,25 @@ void QQuickOverlay::geometryChanged(const QRectF &newGeometry, const QRectF &old
void QQuickOverlay::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickOverlay);
- d->handlePress(event);
+ d->handleMouseEvent(this, event);
}
void QQuickOverlay::mouseMoveEvent(QMouseEvent *event)
{
Q_D(QQuickOverlay);
- d->handleMove(event);
+ d->handleMouseEvent(this, event);
}
void QQuickOverlay::mouseReleaseEvent(QMouseEvent *event)
{
Q_D(QQuickOverlay);
- d->handleRelease(event);
+ d->handleMouseEvent(this, event);
}
void QQuickOverlay::touchEvent(QTouchEvent *event)
{
Q_D(QQuickOverlay);
- switch (event->type()) {
- case QEvent::TouchBegin:
- d->handlePress(event);
- break;
-
- case QEvent::TouchUpdate:
- for (const QTouchEvent::TouchPoint &point : event->touchPoints()) {
- switch (point.state()) {
- case Qt::TouchPointPressed:
- d->handlePress(event);
- break;
- case Qt::TouchPointMoved:
- d->handleMove(event);
- break;
- case Qt::TouchPointReleased:
- d->handleRelease(event);
- break;
- default:
- break;
- }
- }
- break;
-
- case QEvent::TouchEnd:
- d->handleRelease(event);
- break;
-
- default:
- QQuickItem::touchEvent(event);
- break;
- }
+ d->handleTouchEvent(this, event);
}
#if QT_CONFIG(wheelevent)
@@ -468,19 +517,16 @@ bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event)
// does not have background dimming.
if (item == p->dimmer || !p->popupItem->isAncestorOf(item)) {
switch (event->type()) {
+ case QEvent::TouchBegin:
+ case QEvent::TouchUpdate:
+ case QEvent::TouchEnd:
+ return d->handleTouchEvent(item, static_cast<QTouchEvent *>(event), popup);
+
case QEvent::MouseButtonPress:
- emit pressed();
- if (popup->overlayEvent(item, event)) {
- d->setMouseGrabberPopup(popup);
- return true;
- }
- break;
case QEvent::MouseMove:
- return popup->overlayEvent(item, event);
case QEvent::MouseButtonRelease:
- emit released();
- d->setMouseGrabberPopup(nullptr);
- return popup->overlayEvent(item, event);
+ return d->handleMouseEvent(item, static_cast<QMouseEvent *>(event), popup);
+
default:
break;
}
diff --git a/src/quicktemplates2/qquickoverlay_p_p.h b/src/quicktemplates2/qquickoverlay_p_p.h
index c9d887bd..de8539c9 100644
--- a/src/quicktemplates2/qquickoverlay_p_p.h
+++ b/src/quicktemplates2/qquickoverlay_p_p.h
@@ -70,9 +70,13 @@ public:
return overlay->d_func();
}
- void handlePress(QEvent *event);
- void handleMove(QEvent *event);
- void handleRelease(QEvent *event);
+ bool startDrag(QEvent *event);
+ bool handlePress(QQuickItem *source, QEvent *event, QQuickPopup *target);
+ bool handleMove(QQuickItem *source, QEvent *event, QQuickPopup *target);
+ bool handleRelease(QQuickItem *source, QEvent *event, QQuickPopup *target);
+
+ bool handleMouseEvent(QQuickItem *source, QMouseEvent *event, QQuickPopup *target = nullptr);
+ bool handleTouchEvent(QQuickItem *source, QTouchEvent *event, QQuickPopup *target = nullptr);
void addPopup(QQuickPopup *popup);
void removePopup(QQuickPopup *popup);
diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp
index a0302417..775d4e6a 100644
--- a/src/quicktemplates2/qquickpopup.cpp
+++ b/src/quicktemplates2/qquickpopup.cpp
@@ -44,7 +44,6 @@
#include "qquickdialog_p.h"
#include <QtQml/qqmlinfo.h>
-#include <QtQml/private/qqmlnullablevalue_p.h>
#include <QtQuick/qquickitem.h>
#include <QtQuick/private/qquicktransition_p.h>
#include <QtQuick/private/qquickitem_p.h>
@@ -274,46 +273,19 @@ void QQuickPopupPrivate::closeOrReject()
q->close();
}
-bool QQuickPopupPrivate::tryClose(QQuickItem *item, QEvent *event)
+bool QQuickPopupPrivate::tryClose(const QPointF &pos, QQuickPopup::ClosePolicy flags)
{
if (!interactive)
return false;
- bool isPress = false;
- QQmlNullableValue<QPointF> pos;
+ static const QQuickPopup::ClosePolicy outsideFlags = QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnReleaseOutside;
+ static const QQuickPopup::ClosePolicy outsideParentFlags = QQuickPopup::CloseOnPressOutsideParent | QQuickPopup::CloseOnReleaseOutsideParent;
- switch (event->type()) {
- case QEvent::MouseButtonPress:
- case QEvent::MouseButtonRelease:
- pos = static_cast<QMouseEvent *>(event)->pos();
- isPress = event->type() == QEvent::MouseButtonPress;
- break;
-
- case QEvent::TouchBegin:
- case QEvent::TouchUpdate:
- case QEvent::TouchEnd:
- for (const QTouchEvent::TouchPoint &point : static_cast<QTouchEvent *>(event)->touchPoints()) {
- if (point.state() == Qt::TouchPointMoved)
- continue;
-
- pos = point.pos();
- isPress = point.state() == Qt::TouchPointPressed;
- break; // TODO: multiple touch points
- }
- break;
-
- default:
- break;
- }
-
- if (pos.isNull) // ignore touch moves
- return false;
-
- const bool onOutside = closePolicy.testFlag(isPress ? QQuickPopup::CloseOnPressOutside : QQuickPopup::CloseOnReleaseOutside);
- const bool onOutsideParent = closePolicy.testFlag(isPress ? QQuickPopup::CloseOnPressOutsideParent : QQuickPopup::CloseOnReleaseOutsideParent);
+ const bool onOutside = closePolicy & (flags & outsideFlags);
+ const bool onOutsideParent = closePolicy & (flags & outsideParentFlags);
if (onOutside || onOutsideParent) {
- if (!popupItem->contains(item->mapToItem(popupItem, pos))) {
- if (!onOutsideParent || !parentItem || !parentItem->contains(item->mapToItem(parentItem, pos))) {
+ if (!popupItem->contains(popupItem->mapFromScene(pos))) {
+ if (!onOutsideParent || !parentItem || !parentItem->contains(parentItem->mapFromScene(pos))) {
closeOrReject();
return true;
}
@@ -335,17 +307,34 @@ bool QQuickPopupPrivate::acceptTouch(const QTouchEvent::TouchPoint &point)
return false;
}
-void QQuickPopupPrivate::handlePress(const QPointF &)
+bool QQuickPopupPrivate::blockInput(QQuickItem *item, const QPointF &point) const
{
+ // don't block presses and releases
+ // a) outside a non-modal popup,
+ // b) to popup children/content, or
+ // b) outside a modal popups's background dimming
+ return modal && !popupItem->isAncestorOf(item) && (!dimmer || dimmer->contains(dimmer->mapFromScene(point)));
}
-void QQuickPopupPrivate::handleMove(const QPointF &)
+bool QQuickPopupPrivate::handlePress(QQuickItem *item, const QPointF &point, ulong timestamp)
{
+ Q_UNUSED(timestamp);
+ tryClose(point, QQuickPopup::CloseOnPressOutside | QQuickPopup::CloseOnPressOutsideParent);
+ return blockInput(item, point);
}
-void QQuickPopupPrivate::handleRelease(const QPointF &)
+bool QQuickPopupPrivate::handleMove(QQuickItem *item, const QPointF &point, ulong timestamp)
{
+ Q_UNUSED(timestamp);
+ return blockInput(item, point);
+}
+
+bool QQuickPopupPrivate::handleRelease(QQuickItem *item, const QPointF &point, ulong timestamp)
+{
+ Q_UNUSED(timestamp);
+ tryClose(point, QQuickPopup::CloseOnReleaseOutside | QQuickPopup::CloseOnReleaseOutsideParent);
touchId = -1;
+ return blockInput(item, point);
}
void QQuickPopupPrivate::handleUngrab()
@@ -360,6 +349,68 @@ void QQuickPopupPrivate::handleUngrab()
touchId = -1;
}
+bool QQuickPopupPrivate::handleMouseEvent(QQuickItem *item, QMouseEvent *event)
+{
+ QPointF pos = item->mapToScene(event->localPos());
+ switch (event->type()) {
+ case QEvent::MouseButtonPress:
+ return handlePress(item, pos, event->timestamp());
+ case QEvent::MouseMove:
+ return handleMove(item, pos, event->timestamp());
+ case QEvent::MouseButtonRelease:
+ return handleRelease(item, pos, event->timestamp());
+ default:
+ Q_UNREACHABLE();
+ return false;
+ }
+}
+
+bool QQuickPopupPrivate::handleTouchEvent(QQuickItem *item, QTouchEvent *event)
+{
+ switch (event->type()) {
+ case QEvent::TouchBegin:
+ for (const QTouchEvent::TouchPoint &point : event->touchPoints()) {
+ if (acceptTouch(point))
+ return handlePress(item, item->mapToScene(point.pos()), event->timestamp());
+ }
+ break;
+
+ case QEvent::TouchUpdate:
+ for (const QTouchEvent::TouchPoint &point : event->touchPoints()) {
+ if (!acceptTouch(point))
+ continue;
+
+ switch (point.state()) {
+ case Qt::TouchPointPressed:
+ return handlePress(item, item->mapToScene(point.pos()), event->timestamp());
+ case Qt::TouchPointMoved:
+ return handleMove(item, item->mapToScene(point.pos()), event->timestamp());
+ case Qt::TouchPointReleased:
+ return handleRelease(item, item->mapToScene(point.pos()), event->timestamp());
+ default:
+ break;
+ }
+ }
+ break;
+
+ case QEvent::TouchEnd:
+ for (const QTouchEvent::TouchPoint &point : event->touchPoints()) {
+ if (acceptTouch(point))
+ return handleRelease(item, item->mapToScene(point.pos()), event->timestamp());
+ }
+ break;
+
+ case QEvent::TouchCancel:
+ handleUngrab();
+ break;
+
+ default:
+ break;
+ }
+
+ return false;
+}
+
bool QQuickPopupPrivate::prepareEnterTransition()
{
Q_Q(QQuickPopup);
@@ -1873,21 +1924,21 @@ void QQuickPopup::keyReleaseEvent(QKeyEvent *event)
void QQuickPopup::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickPopup);
- d->handlePress(event->localPos());
+ d->handleMouseEvent(d->popupItem, event);
event->accept();
}
void QQuickPopup::mouseMoveEvent(QMouseEvent *event)
{
Q_D(QQuickPopup);
- d->handleMove(event->localPos());
+ d->handleMouseEvent(d->popupItem, event);
event->accept();
}
void QQuickPopup::mouseReleaseEvent(QMouseEvent *event)
{
Q_D(QQuickPopup);
- d->handleRelease(event->localPos());
+ d->handleMouseEvent(d->popupItem, event);
event->accept();
}
@@ -1917,12 +1968,11 @@ bool QQuickPopup::overlayEvent(QQuickItem *item, QEvent *event)
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
+ return d->handleTouchEvent(item, static_cast<QTouchEvent *>(event));
+
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
- if (d->modal)
- event->accept();
- d->tryClose(item, event);
- return d->modal;
+ return d->handleMouseEvent(item, static_cast<QMouseEvent *>(event));
default:
return false;
@@ -1932,52 +1982,7 @@ bool QQuickPopup::overlayEvent(QQuickItem *item, QEvent *event)
void QQuickPopup::touchEvent(QTouchEvent *event)
{
Q_D(QQuickPopup);
- switch (event->type()) {
- case QEvent::TouchBegin:
- for (const QTouchEvent::TouchPoint &point : event->touchPoints()) {
- if (d->acceptTouch(point))
- d->handlePress(point.pos());
- }
- break;
-
- case QEvent::TouchUpdate:
- for (const QTouchEvent::TouchPoint &point : event->touchPoints()) {
- if (!d->acceptTouch(point))
- continue;
-
- switch (point.state()) {
- case Qt::TouchPointPressed:
- d->handlePress(point.pos());
- break;
- case Qt::TouchPointMoved:
- d->handleMove(point.pos());
- break;
- case Qt::TouchPointReleased:
- d->handleRelease(point.pos());
- break;
- default:
- break;
- }
- }
- break;
-
- case QEvent::TouchEnd:
- for (const QTouchEvent::TouchPoint &point : event->touchPoints()) {
- if (d->acceptTouch(point))
- d->handleRelease(point.pos());
- }
- break;
-
- case QEvent::TouchCancel:
- d->handleUngrab();
- break;
-
- default:
- break;
- }
-
- // TODO: QQuickPopup still relies on synthesized mouse events
- event->ignore();
+ d->handleTouchEvent(d->popupItem, event);
}
void QQuickPopup::touchUngrabEvent()
diff --git a/src/quicktemplates2/qquickpopup_p_p.h b/src/quicktemplates2/qquickpopup_p_p.h
index 51e9cf2f..476e691d 100644
--- a/src/quicktemplates2/qquickpopup_p_p.h
+++ b/src/quicktemplates2/qquickpopup_p_p.h
@@ -95,14 +95,19 @@ public:
void init();
void closeOrReject();
- bool tryClose(QQuickItem *item, QEvent *event);
+ bool tryClose(const QPointF &pos, QQuickPopup::ClosePolicy flags);
virtual bool acceptTouch(const QTouchEvent::TouchPoint &point);
- virtual void handlePress(const QPointF &point);
- virtual void handleMove(const QPointF &point);
- virtual void handleRelease(const QPointF &point);
+ virtual bool blockInput(QQuickItem *item, const QPointF &point) const;
+
+ virtual bool handlePress(QQuickItem* item, const QPointF &point, ulong timestamp);
+ virtual bool handleMove(QQuickItem* item, const QPointF &point, ulong timestamp);
+ virtual bool handleRelease(QQuickItem* item, const QPointF &point, ulong timestamp);
virtual void handleUngrab();
+ bool handleMouseEvent(QQuickItem *item, QMouseEvent *event);
+ bool handleTouchEvent(QQuickItem *item, QTouchEvent *event);
+
virtual void reposition();
virtual void resizeOverlay();
diff --git a/src/quicktemplates2/qquickrangeslider.cpp b/src/quicktemplates2/qquickrangeslider.cpp
index 1468d358..f1e8a01e 100644
--- a/src/quicktemplates2/qquickrangeslider.cpp
+++ b/src/quicktemplates2/qquickrangeslider.cpp
@@ -435,16 +435,15 @@ void QQuickRangeSliderPrivate::handlePress(const QPointF &point)
otherNode = first;
} else {
// find the nearest
- const qreal firstDistance = QLineF(firstHandle->boundingRect().center(),
- q->mapToItem(firstHandle, point)).length();
- const qreal secondDistance = QLineF(secondHandle->boundingRect().center(),
- q->mapToItem(secondHandle, point)).length();
+ const qreal firstPos = positionAt(q, firstHandle, point);
+ const qreal secondPos = positionAt(q, secondHandle, point);
+ const qreal firstDistance = qAbs(firstPos - first->position());
+ const qreal secondDistance = qAbs(secondPos - second->position());
if (qFuzzyCompare(firstDistance, secondDistance)) {
// same distance => choose the one that can be moved towards the press position
const bool inverted = from > to;
- const qreal pos = positionAt(q, firstHandle, point);
- if ((!inverted && pos < first->position()) || (inverted && pos > first->position())) {
+ if ((!inverted && firstPos < first->position()) || (inverted && firstPos > first->position())) {
hitNode = first;
otherNode = second;
} else {
@@ -462,11 +461,14 @@ void QQuickRangeSliderPrivate::handlePress(const QPointF &point)
if (hitNode) {
hitNode->setPressed(true);
- hitNode->handle()->setZ(1);
+ if (QQuickItem *handle = hitNode->handle())
+ handle->setZ(1);
QQuickRangeSliderNodePrivate::get(hitNode)->touchId = touchId;
}
- if (otherNode)
- otherNode->handle()->setZ(0);
+ if (otherNode) {
+ if (QQuickItem *handle = otherNode->handle())
+ handle->setZ(0);
+ }
}
void QQuickRangeSliderPrivate::handleMove(const QPointF &point)
diff --git a/src/quicktemplates2/qquickspinbox.cpp b/src/quicktemplates2/qquickspinbox.cpp
index b6da0c9f..07bf4121 100644
--- a/src/quicktemplates2/qquickspinbox.cpp
+++ b/src/quicktemplates2/qquickspinbox.cpp
@@ -766,6 +766,16 @@ void QQuickSpinBox::decrease()
d->stepBy(-d->effectiveStepSize());
}
+void QQuickSpinBox::focusInEvent(QFocusEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::focusInEvent(event);
+
+ // When an editable SpinBox gets focus, it must pass on the focus to its editor.
+ if (d->editable && d->contentItem && !d->contentItem->hasActiveFocus())
+ d->contentItem->forceActiveFocus(event->reason());
+}
+
void QQuickSpinBox::hoverEnterEvent(QHoverEvent *event)
{
Q_D(QQuickSpinBox);
diff --git a/src/quicktemplates2/qquickspinbox_p.h b/src/quicktemplates2/qquickspinbox_p.h
index d1b42497..27956d7c 100644
--- a/src/quicktemplates2/qquickspinbox_p.h
+++ b/src/quicktemplates2/qquickspinbox_p.h
@@ -132,6 +132,7 @@ Q_SIGNALS:
Q_REVISION(3) void wrapChanged();
protected:
+ void focusInEvent(QFocusEvent *event) override;
void hoverEnterEvent(QHoverEvent *event) override;
void hoverMoveEvent(QHoverEvent *event) override;
void hoverLeaveEvent(QHoverEvent *event) override;
diff --git a/tests/auto/controls/data/tst_container.qml b/tests/auto/controls/data/tst_container.qml
index 684f0931..049982fb 100644
--- a/tests/auto/controls/data/tst_container.qml
+++ b/tests/auto/controls/data/tst_container.qml
@@ -90,4 +90,40 @@ TestCase {
compare(control.implicitWidth, 210)
compare(control.implicitHeight, 220)
}
+
+ function test_currentIndex() {
+ var control1 = createTemporaryObject(container, testCase)
+ verify(control1)
+
+ var control2 = createTemporaryObject(container, testCase)
+ verify(control2)
+
+ compare(control1.currentIndex, -1)
+ compare(control2.currentIndex, -1)
+
+ for (var i = 0; i < 3; ++i) {
+ control1.addItem(rectangle.createObject(control1))
+ control2.addItem(rectangle.createObject(control2))
+ }
+
+ compare(control1.count, 3)
+ compare(control2.count, 3)
+ compare(control1.currentIndex, 0)
+ compare(control2.currentIndex, 0)
+
+ control1.currentIndex = Qt.binding(function() { return control2.currentIndex })
+ control2.currentIndex = Qt.binding(function() { return control1.currentIndex })
+
+ control1.setCurrentIndex(1)
+ compare(control1.currentIndex, 1)
+ compare(control2.currentIndex, 1)
+
+ control1.incrementCurrentIndex()
+ compare(control1.currentIndex, 2)
+ compare(control2.currentIndex, 2)
+
+ control2.decrementCurrentIndex()
+ compare(control1.currentIndex, 1)
+ compare(control2.currentIndex, 1)
+ }
}
diff --git a/tests/auto/controls/data/tst_dial.qml b/tests/auto/controls/data/tst_dial.qml
index 3955e60d..33b0dbea 100644
--- a/tests/auto/controls/data/tst_dial.qml
+++ b/tests/auto/controls/data/tst_dial.qml
@@ -579,4 +579,17 @@ TestCase {
compare(control.value, 2.5)
compare(control.position, 0.25)
}
+
+ function test_nullHandle() {
+ var control = createTemporaryObject(dialComponent, testCase)
+ verify(control)
+
+ control.handle = null
+
+ mousePress(control)
+ verify(control.pressed, true)
+
+ mouseRelease(control)
+ compare(control.pressed, false)
+ }
}
diff --git a/tests/auto/controls/data/tst_dialog.qml b/tests/auto/controls/data/tst_dialog.qml
index 6b18a323..2f3d2a6b 100644
--- a/tests/auto/controls/data/tst_dialog.qml
+++ b/tests/auto/controls/data/tst_dialog.qml
@@ -87,8 +87,12 @@ TestCase {
function test_accept() {
var control = createTemporaryObject(dialog, testCase)
+ var openedSpy = createTemporaryObject(signalSpy, testCase, {target: control, signalName: "opened"})
+ verify(openedSpy.valid)
+
control.open()
- waitForRendering(control.contentItem)
+ openedSpy.wait()
+ compare(openedSpy.count, 1)
verify(control.visible)
var acceptedSpy = createTemporaryObject(signalSpy, testCase, {target: control, signalName: "accepted"})
@@ -102,8 +106,12 @@ TestCase {
function test_reject() {
var control = createTemporaryObject(dialog, testCase)
+ var openedSpy = createTemporaryObject(signalSpy, testCase, {target: control, signalName: "opened"})
+ verify(openedSpy.valid)
+
control.open()
- waitForRendering(control.contentItem)
+ openedSpy.wait()
+ compare(openedSpy.count, 1)
verify(control.visible)
var rejectedSpy = createTemporaryObject(signalSpy, testCase, {target: control, signalName: "rejected"})
@@ -226,8 +234,12 @@ TestCase {
var control = createTemporaryObject(dialog, testCase, {width: 100, height: 100})
verify(control)
+ var openedSpy = createTemporaryObject(signalSpy, testCase, {target: control, signalName: "opened"})
+ verify(openedSpy.valid)
+
control.open()
- waitForRendering(control.contentItem)
+ openedSpy.wait()
+ compare(openedSpy.count, 1)
verify(control.visible)
compare(control.width, 100)
@@ -315,8 +327,12 @@ TestCase {
var control = createTemporaryObject(dialog, testCase, {spacing: 20, width: 100, height: 100})
verify(control)
+ var openedSpy = createTemporaryObject(signalSpy, testCase, {target: control, signalName: "opened"})
+ verify(openedSpy.valid)
+
control.open()
- waitForRendering(control.contentItem)
+ openedSpy.wait()
+ compare(openedSpy.count, 1)
verify(control.visible)
control.contentItem.visible = data.content
diff --git a/tests/auto/controls/data/tst_popup.qml b/tests/auto/controls/data/tst_popup.qml
index 24465db1..beae39d1 100644
--- a/tests/auto/controls/data/tst_popup.qml
+++ b/tests/auto/controls/data/tst_popup.qml
@@ -936,8 +936,13 @@ TestCase {
var control = createTemporaryObject(popupControl, testCase)
verify(control)
+ var openedSpy = createTemporaryObject(signalSpy, testCase, {target: control, signalName: "opened"})
+ verify(openedSpy.valid)
+
control.open()
- waitForRendering(control.contentItem)
+ openedSpy.wait()
+ compare(openedSpy.count, 1)
+ verify(control.visible)
// implicit size of the content
control.contentItem.implicitWidth = 10
diff --git a/tests/auto/controls/data/tst_rangeslider.qml b/tests/auto/controls/data/tst_rangeslider.qml
index 3d197f83..01ac1b8f 100644
--- a/tests/auto/controls/data/tst_rangeslider.qml
+++ b/tests/auto/controls/data/tst_rangeslider.qml
@@ -903,4 +903,31 @@ TestCase {
mouseMove(control, node.handle.x - 1, node.handle.y - 1)
compare(node.hovered, false)
}
+
+ function test_nullHandles() {
+ var control = createTemporaryObject(sliderComponent, testCase, {"second.value": 1})
+ verify(control)
+
+ verify(control.first.handle)
+ verify(control.second.handle)
+
+ control.first.handle = null
+ control.second.handle = null
+
+ mousePress(control, control.leftPadding, control.height / 2)
+ verify(control.first.pressed, true)
+ compare(control.second.pressed, false)
+
+ mouseRelease(control, control.leftPadding, control.height / 2)
+ compare(control.first.pressed, false)
+ compare(control.second.pressed, false)
+
+ mousePress(control, control.width - control.rightPadding, control.height / 2)
+ compare(control.first.pressed, false)
+ compare(control.second.pressed, true)
+
+ mouseRelease(control, control.width - control.rightPadding, control.height / 2)
+ compare(control.first.pressed, false)
+ compare(control.second.pressed, false)
+ }
}
diff --git a/tests/auto/controls/data/tst_slider.qml b/tests/auto/controls/data/tst_slider.qml
index 826a17d2..b70aeaab 100644
--- a/tests/auto/controls/data/tst_slider.qml
+++ b/tests/auto/controls/data/tst_slider.qml
@@ -789,4 +789,17 @@ TestCase {
compare(control.valueAt(0.5), data.values[2])
compare(control.valueAt(1.0), data.values[3])
}
+
+ function test_nullHandle() {
+ var control = createTemporaryObject(slider, testCase)
+ verify(control)
+
+ control.handle = null
+
+ mousePress(control)
+ verify(control.pressed, true)
+
+ mouseRelease(control)
+ compare(control.pressed, false)
+ }
}
diff --git a/tests/auto/controls/data/tst_spinbox.qml b/tests/auto/controls/data/tst_spinbox.qml
index 6c4f15c5..17e4b592 100644
--- a/tests/auto/controls/data/tst_spinbox.qml
+++ b/tests/auto/controls/data/tst_spinbox.qml
@@ -51,6 +51,7 @@
import QtQuick 2.2
import QtTest 1.0
import QtQuick.Controls 2.2
+import QtQuick.Window 2.3
TestCase {
id: testCase
@@ -399,6 +400,16 @@ TestCase {
compare(control.value, 100)
}
+ function test_initialFocus() {
+ var window = testCase.Window.window
+ verify(window)
+ compare(window.activeFocusItem, window.contentItem)
+
+ var control = createTemporaryObject(spinBox, testCase, { editable: true, focus: true })
+ verify(control)
+ tryCompare(control.contentItem, "activeFocus", true)
+ }
+
function test_editable() {
var control = createTemporaryObject(spinBox, testCase)
verify(control)
diff --git a/tests/auto/drawer/tst_drawer.cpp b/tests/auto/drawer/tst_drawer.cpp
index 251f5567..7fd4f0d9 100644
--- a/tests/auto/drawer/tst_drawer.cpp
+++ b/tests/auto/drawer/tst_drawer.cpp
@@ -58,6 +58,8 @@ class tst_Drawer : public QQmlDataTest
Q_OBJECT
private slots:
+ void initTestCase();
+
void visible_data();
void visible();
@@ -89,6 +91,13 @@ private slots:
void interactive();
};
+
+void tst_Drawer::initTestCase()
+{
+ QQmlDataTest::initTestCase();
+ qputenv("QML_NO_TOUCH_COMPRESSION", "1");
+}
+
void tst_Drawer::visible_data()
{
QTest::addColumn<QString>("source");
@@ -240,19 +249,21 @@ void tst_Drawer::state()
void tst_Drawer::position_data()
{
QTest::addColumn<Qt::Edge>("edge");
+ QTest::addColumn<QPoint>("press");
QTest::addColumn<QPoint>("from");
QTest::addColumn<QPoint>("to");
QTest::addColumn<qreal>("position");
- QTest::newRow("top") << Qt::TopEdge << QPoint(100, 0) << QPoint(100, 100) << qreal(0.5);
- QTest::newRow("left") << Qt::LeftEdge << QPoint(0, 100) << QPoint(100, 100) << qreal(0.5);
- QTest::newRow("right") << Qt::RightEdge << QPoint(399, 100) << QPoint(300, 100) << qreal(0.5);
- QTest::newRow("bottom") << Qt::BottomEdge << QPoint(100, 399) << QPoint(100, 300) << qreal(0.5);
+ QTest::newRow("top") << Qt::TopEdge << QPoint(100, 0) << QPoint(100, 50) << QPoint(100, 150) << qreal(0.5);
+ QTest::newRow("left") << Qt::LeftEdge << QPoint(0, 100) << QPoint(50, 100) << QPoint(150, 100) << qreal(0.5);
+ QTest::newRow("right") << Qt::RightEdge << QPoint(399, 100) << QPoint(350, 100) << QPoint(250, 100) << qreal(0.5);
+ QTest::newRow("bottom") << Qt::BottomEdge << QPoint(100, 399) << QPoint(100, 350) << QPoint(150, 250) << qreal(0.5);
}
void tst_Drawer::position()
{
QFETCH(Qt::Edge, edge);
+ QFETCH(QPoint, press);
QFETCH(QPoint, from);
QFETCH(QPoint, to);
QFETCH(qreal, position);
@@ -268,7 +279,8 @@ void tst_Drawer::position()
QVERIFY(drawer);
drawer->setEdge(edge);
- QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, from);
+ QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, press);
+ QTest::mouseMove(window, from);
QTest::mouseMove(window, to);
QCOMPARE(drawer->position(), position);
@@ -314,26 +326,30 @@ void tst_Drawer::dragMargin()
drawer->setEdge(edge);
drawer->setDragMargin(dragMargin);
+ const int startDragDistance = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5) + 1;
+
// drag from the left
int leftX = qMax<int>(0, dragMargin);
- int leftDistance = drawer->width() * 0.45;
+ int leftDistance = startDragDistance + drawer->width() * 0.45;
QVERIFY(leftDistance > QGuiApplication::styleHints()->startDragDistance());
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(leftX, drawer->height() / 2));
- QTest::mouseMove(window, QPoint(leftDistance, drawer->height() / 2));
+ QTest::mouseMove(window, QPoint(leftX + startDragDistance, drawer->height() / 2));
+ QTest::mouseMove(window, QPoint(leftX + leftDistance, drawer->height() / 2));
QCOMPARE(drawer->position(), dragFromLeft);
- QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(leftDistance, drawer->height() / 2));
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(leftX + leftDistance, drawer->height() / 2));
drawer->close();
QTRY_COMPARE(drawer->position(), qreal(0.0));
// drag from the right
int rightX = qMin<int>(window->width() - 1, window->width() - dragMargin);
- int rightDistance = drawer->width() * 0.75;
+ int rightDistance = startDragDistance + drawer->width() * 0.75;
QVERIFY(rightDistance > QGuiApplication::styleHints()->startDragDistance());
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(rightX, drawer->height() / 2));
- QTest::mouseMove(window, QPoint(window->width() - rightDistance, drawer->height() / 2));
+ QTest::mouseMove(window, QPoint(rightX - startDragDistance, drawer->height() / 2));
+ QTest::mouseMove(window, QPoint(rightX - rightDistance, drawer->height() / 2));
QCOMPARE(drawer->position(), dragFromRight);
- QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - rightDistance, drawer->height() / 2));
+ QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(rightX - rightDistance, drawer->height() / 2));
}
static QRectF geometry(const QQuickItem *item)
@@ -620,7 +636,8 @@ void tst_Drawer::multiple()
// drag the left drawer open
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(0, window->height() / 2));
- QTest::mouseMove(window, QPoint(leftDrawer->width() / 2, window->height() / 2));
+ QTest::mouseMove(window, QPoint(leftDrawer->width() / 4, window->height() / 2));
+ QTest::mouseMove(window, QPoint(leftDrawer->width() / 4 * 3, window->height() / 2));
QCOMPARE(leftDrawer->position(), 0.5);
QCOMPARE(rightDrawer->position(), 0.0);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(leftDrawer->width() / 2, window->height() / 2));
@@ -699,7 +716,8 @@ void tst_Drawer::multiple()
// drag the right drawer open
QTest::mousePress(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - 1, window->height() / 2));
- QTest::mouseMove(window, QPoint(window->width() - rightDrawer->width() / 2, window->height() / 2));
+ QTest::mouseMove(window, QPoint(window->width() - rightDrawer->width() / 4, window->height() / 2));
+ QTest::mouseMove(window, QPoint(window->width() - rightDrawer->width() / 4 * 3, window->height() / 2));
QCOMPARE(rightDrawer->position(), 0.5);
QCOMPARE(leftDrawer->position(), 0.0);
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(window->width() - rightDrawer->width() / 2, window->height() / 2));
@@ -746,19 +764,18 @@ void tst_Drawer::touch()
// drag to open
QTest::touchEvent(window, device.data()).press(0, QPoint(0, 100));
- QTest::touchEvent(window, device.data()).move(0, QPoint(100, 100));
+ QTest::touchEvent(window, device.data()).move(0, QPoint(50, 100));
+ QTest::touchEvent(window, device.data()).move(0, QPoint(150, 100));
QTRY_COMPARE(drawer->position(), 0.5);
- QTest::touchEvent(window, device.data()).release(0, QPoint(100, 100));
+ QTest::touchEvent(window, device.data()).release(0, QPoint(150, 100));
QVERIFY(drawerOpenedSpy.wait());
QCOMPARE(drawer->position(), 1.0);
// drag to close
QTest::touchEvent(window, device.data()).press(0, QPoint(300, 100));
QTest::touchEvent(window, device.data()).move(0, QPoint(300 - drawer->dragMargin(), 100));
- for (int x = 300; x > 100; x -= 10) {
+ for (int x = 300; x > 100; x -= 10)
QTest::touchEvent(window, device.data()).move(0, QPoint(x, 100));
- QQuickWindowPrivate::get(window)->flushFrameSynchronousEvents();
- }
QTest::touchEvent(window, device.data()).move(0, QPoint(100, 100));
QTRY_COMPARE(drawer->position(), 0.5);
QTest::touchEvent(window, device.data()).release(0, QPoint(100, 100));
diff --git a/tests/auto/focus/data/keyNavigation.qml b/tests/auto/focus/data/keyNavigation.qml
index 98a58ab5..ba7d5807 100644
--- a/tests/auto/focus/data/keyNavigation.qml
+++ b/tests/auto/focus/data/keyNavigation.qml
@@ -191,7 +191,6 @@ Item {
SpinBox {
id: spinbox
objectName: "spinbox"
- editable: true
value: 50
KeyNavigation.left: radiobutton2
KeyNavigation.right: swtich
diff --git a/tests/auto/popup/tst_popup.cpp b/tests/auto/popup/tst_popup.cpp
index a6de0c03..0e9b55f7 100644
--- a/tests/auto/popup/tst_popup.cpp
+++ b/tests/auto/popup/tst_popup.cpp
@@ -160,13 +160,26 @@ void tst_popup::state()
void tst_popup::overlay_data()
{
QTest::addColumn<QString>("source");
- QTest::newRow("Window") << "window.qml";
- QTest::newRow("ApplicationWindow") << "applicationwindow.qml";
+ QTest::addColumn<bool>("modal");
+ QTest::addColumn<bool>("dim");
+
+ QTest::newRow("Window") << "window.qml" << false << false;
+ QTest::newRow("Window,dim") << "window.qml" << false << true;
+ QTest::newRow("Window,modal") << "window.qml" << true << false;
+ QTest::newRow("Window,modal,dim") << "window.qml" << true << true;
+
+ QTest::newRow("ApplicationWindow") << "applicationwindow.qml" << false << false;
+ QTest::newRow("ApplicationWindow,dim") << "applicationwindow.qml" << false << true;
+ QTest::newRow("ApplicationWindow,modal") << "applicationwindow.qml" << true << false;
+ QTest::newRow("ApplicationWindow,modal,dim") << "applicationwindow.qml" << true << true;
}
void tst_popup::overlay()
{
QFETCH(QString, source);
+ QFETCH(bool, modal);
+ QFETCH(bool, dim);
+
QQuickApplicationHelper helper(this, source);
QQuickWindow *window = helper.window;
@@ -210,7 +223,8 @@ void tst_popup::overlay()
QVERIFY(!popup->isVisible());
QVERIFY(!overlay->isVisible());
- popup->setModal(true);
+ popup->setDim(dim);
+ popup->setModal(modal);
popup->setClosePolicy(QQuickPopup::CloseOnReleaseOutside);
popup->open();
@@ -223,10 +237,20 @@ void tst_popup::overlay()
QTest::mouseRelease(window, Qt::LeftButton, Qt::NoModifier, QPoint(1, 1));
QCOMPARE(overlayPressedSignal.count(), 2);
+
+ #define comment "Non-modal popups do not yet support CloseOnReleaseXxx"
+ #define QEXPECT_NON_MODAL_POPUP_FAILS() \
+ QEXPECT_FAIL("Window", comment, Continue); \
+ QEXPECT_FAIL("Window,dim", comment, Continue); \
+ QEXPECT_FAIL("ApplicationWindow", comment, Continue); \
+ QEXPECT_FAIL("ApplicationWindow,dim", comment, Continue);
+
+ QEXPECT_NON_MODAL_POPUP_FAILS()
QCOMPARE(overlayReleasedSignal.count(), 1);
+ QEXPECT_NON_MODAL_POPUP_FAILS()
QVERIFY(!popup->isVisible());
- QVERIFY(!overlay->isVisible());
+ QCOMPARE(overlay->isVisible(), popup->isVisible());
}
void tst_popup::zOrder_data()