diff options
Diffstat (limited to 'src/quick')
22 files changed, 365 insertions, 89 deletions
diff --git a/src/quick/accessible/qaccessiblequickitem.cpp b/src/quick/accessible/qaccessiblequickitem.cpp index 5e1ae25c38..85719fdc80 100644 --- a/src/quick/accessible/qaccessiblequickitem.cpp +++ b/src/quick/accessible/qaccessiblequickitem.cpp @@ -216,6 +216,8 @@ QAccessible::Role QAccessibleQuickItem::role() const if (role == QAccessible::NoRole) { if (qobject_cast<QQuickText*>(const_cast<QQuickItem *>(item()))) role = QAccessible::StaticText; + else if (qobject_cast<QQuickTextInput*>(const_cast<QQuickItem *>(item()))) + role = QAccessible::EditableText; else role = QAccessible::Client; } @@ -232,6 +234,7 @@ QStringList QAccessibleQuickItem::actionNames() const { QStringList actions; switch (role()) { + case QAccessible::Link: case QAccessible::PushButton: actions << QAccessibleActionInterface::pressAction(); break; diff --git a/src/quick/designer/qquickdesignersupportproperties.cpp b/src/quick/designer/qquickdesignersupportproperties.cpp index fb6a5fb324..479e77bf68 100644 --- a/src/quick/designer/qquickdesignersupportproperties.cpp +++ b/src/quick/designer/qquickdesignersupportproperties.cpp @@ -126,16 +126,15 @@ void QQuickDesignerSupportProperties::getPropertyCache(QObject *object, QQmlEngi QQmlEnginePrivate::get(engine)->cache(object->metaObject()); } -QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::propertyNameListForWritableProperties(QObject *object, +static QQuickDesignerSupport::PropertyNameList propertyNameListForWritableProperties(QObject *object, const QQuickDesignerSupport::PropertyName &baseName, - QObjectList *inspectedObjects) + QObjectList *inspectedObjects, + int depth = 0) { QQuickDesignerSupport::PropertyNameList propertyNameList; - QObjectList localObjectList; - - if (inspectedObjects == nullptr) - inspectedObjects = &localObjectList; + if (depth > 2) + return propertyNameList; if (!inspectedObjects->contains(object)) inspectedObjects->append(object); @@ -150,14 +149,16 @@ QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::propert if (childObject) propertyNameList.append(propertyNameListForWritableProperties(childObject, baseName + QQuickDesignerSupport::PropertyName(metaProperty.name()) - + '.', inspectedObjects)); + + '.', inspectedObjects, + depth + 1)); } } else if (QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance(qmlEngine(object), metaProperty.userType())) { valueType->setValue(metaProperty.read(object)); propertyNameList.append(propertyNameListForWritableProperties(valueType, baseName + QQuickDesignerSupport::PropertyName(metaProperty.name()) - + '.', inspectedObjects)); + + '.', inspectedObjects, + depth + 1)); } if (metaProperty.isReadable() && metaProperty.isWritable()) { @@ -169,6 +170,12 @@ QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::propert return propertyNameList; } +QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::propertyNameListForWritableProperties(QObject *object) +{ + QObjectList localObjectList; + return ::propertyNameListForWritableProperties(object, {}, &localObjectList); +} + bool QQuickDesignerSupportProperties::isPropertyBlackListed(const QQuickDesignerSupport::PropertyName &propertyName) { if (propertyName.contains(".") && propertyName.contains("__")) @@ -182,7 +189,8 @@ bool QQuickDesignerSupportProperties::isPropertyBlackListed(const QQuickDesigner QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::allPropertyNames(QObject *object, const QQuickDesignerSupport::PropertyName &baseName, - QObjectList *inspectedObjects) + QObjectList *inspectedObjects, + int depth) { QQuickDesignerSupport::PropertyNameList propertyNameList; @@ -191,6 +199,9 @@ QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::allProp if (inspectedObjects == nullptr) inspectedObjects = &localObjectList; + if (depth > 2) + return propertyNameList; + if (!inspectedObjects->contains(object)) inspectedObjects->append(object); @@ -214,7 +225,8 @@ QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::allProp propertyNameList.append(allPropertyNames(childObject, baseName + QQuickDesignerSupport::PropertyName(metaProperty.name()) - + '.', inspectedObjects)); + + '.', inspectedObjects, + depth + 1)); } } else if (QQmlGadgetPtrWrapper *valueType = QQmlGadgetPtrWrapper::instance(qmlEngine(object), metaProperty.userType())) { @@ -223,7 +235,8 @@ QQuickDesignerSupport::PropertyNameList QQuickDesignerSupportProperties::allProp propertyNameList.append(allPropertyNames(valueType, baseName + QQuickDesignerSupport::PropertyName(metaProperty.name()) - + '.', inspectedObjects)); + + '.', inspectedObjects, + depth + 1)); } else { addToPropertyNameListIfNotBlackListed(&propertyNameList, baseName + QQuickDesignerSupport::PropertyName(metaProperty.name())); diff --git a/src/quick/designer/qquickdesignersupportproperties_p.h b/src/quick/designer/qquickdesignersupportproperties_p.h index 02e75ea886..5970eca9f1 100644 --- a/src/quick/designer/qquickdesignersupportproperties_p.h +++ b/src/quick/designer/qquickdesignersupportproperties_p.h @@ -90,12 +90,11 @@ public: static void getPropertyCache(QObject *object, QQmlEngine *engine); static bool isPropertyBlackListed(const QQuickDesignerSupport::PropertyName &propertyName); - static QQuickDesignerSupport::PropertyNameList propertyNameListForWritableProperties(QObject *object, - const QQuickDesignerSupport::PropertyName &baseName = QQuickDesignerSupport::PropertyName(), - QObjectList *inspectedObjects = nullptr); + static QQuickDesignerSupport::PropertyNameList propertyNameListForWritableProperties(QObject *object); static QQuickDesignerSupport::PropertyNameList allPropertyNames(QObject *object, const QQuickDesignerSupport::PropertyName &baseName = QQuickDesignerSupport::PropertyName(), - QObjectList *inspectedObjects = nullptr); + QObjectList *inspectedObjects = nullptr, + int depth = 0); static bool hasFullImplementedListInterface(const QQmlListReference &list); }; diff --git a/src/quick/doc/snippets/pointerHandlers/hoverTapKeyButton.qml b/src/quick/doc/snippets/pointerHandlers/hoverTapKeyButton.qml new file mode 100644 index 0000000000..1564aa16b5 --- /dev/null +++ b/src/quick/doc/snippets/pointerHandlers/hoverTapKeyButton.qml @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the documentation of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:BSD$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** BSD License Usage +** Alternatively, you may use this file under the terms of the BSD license +** as follows: +** +** "Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are +** met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in +** the documentation and/or other materials provided with the +** distribution. +** * Neither the name of The Qt Company Ltd nor the names of its +** contributors may be used to endorse or promote products derived +** from this software without specific prior written permission. +** +** +** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +//![0] +import QtQuick 2.12 + +Rectangle { + id: button + signal clicked + + width: 150; height: 50; radius: 3 + color: tapHandler.pressed ? "goldenrod" : hoverHandler.hovered ? "wheat" : "beige" + border.color: activeFocus ? "brown" : "transparent" + focus: true + + HoverHandler { + id: hoverHandler + } + + TapHandler { + id: tapHandler + onTapped: button.clicked() + } + + Keys.onEnterPressed: button.clicked() +} +//![0] diff --git a/src/quick/doc/snippets/qml/externaldrag.qml b/src/quick/doc/snippets/qml/externaldrag.qml index 97a23293ca..5a88be2d4b 100644 --- a/src/quick/doc/snippets/qml/externaldrag.qml +++ b/src/quick/doc/snippets/qml/externaldrag.qml @@ -48,7 +48,7 @@ ** ****************************************************************************/ //![0] -import QtQuick 2.8 +import QtQuick 2.12 Item { width: 200; height: 200 @@ -59,7 +59,7 @@ Item { color: "green" radius: 5 - Drag.active: dragArea.drag.active + Drag.active: dragHandler.active Drag.dragType: Drag.Automatic Drag.supportedActions: Qt.CopyAction Drag.mimeData: { @@ -72,14 +72,14 @@ Item { text: "Drag me" } - MouseArea { - id: dragArea - anchors.fill: parent - - drag.target: parent - onPressed: parent.grabToImage(function(result) { - parent.Drag.imageSource = result.url - }) + DragHandler { + id: dragHandler + onActiveChanged: + if (active) { + parent.grabToImage(function(result) { + parent.Drag.imageSource = result.url; + }) + } } } } diff --git a/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc b/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc index 2ac9860e6f..bf889a9066 100644 --- a/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc +++ b/src/quick/doc/src/concepts/inputhandlers/qtquickhandlers-index.qdoc @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2018 The Qt Company Ltd. +** Copyright (C) 2021 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the documentation of the Qt Toolkit. @@ -30,20 +30,21 @@ \title Qt Quick Input Handlers \brief A module with a set of QML elements that handle events from input devices in a user interface. - Qt Quick Input Handlers are a set of QML types used to handle events from - keyboard, touch, mouse, and stylus devices in a UI. In contrast to event-handling - items, such as \l MouseArea and \l Flickable, input handlers are explicitly non-visual, - require less memory and are intended to be used in greater numbers: one - handler instance per aspect of interaction. Each input handler instance - handles certain events on behalf of its \c parent Item. Thus the visual and + Qt Quick Input Handlers are a set of QML types used to handle + \l {QInputEvent}{events} from keyboard, touch, mouse, and stylus + \l {QInputDevice}{devices} in a UI. In contrast to event-handling + items, such as \l MouseArea and \l Flickable, input handlers are explicitly + non-visual, require less memory and are intended to be used in greater + numbers: one handler instance per aspect of interaction. Each input handler + instance handles certain events on behalf of its + \l {QQuickPointerHandler::parent()}{parent} Item. Thus the visual and behavioral concerns are better separated, and the behavior is built up by finer-grained composition. - In Qt 5.10, these handlers were introduced in a separate Qt.labs.handlers module. - Now they are included with Qt Quick since 5.12. The pre-existing - \l Keys attached property is similar in concept, so we refer to the - pointing-device-oriented handlers plus \c Keys together as the set of Input Handlers. - We expect to offer more attached-property use cases in future versions of Qt. + The pre-existing \l Keys attached property is similar in concept, so we + refer to the pointing-device-oriented handlers plus \c Keys together as the + set of Input Handlers. We expect to offer more attached-property use cases + in future versions of Qt. \section1 Input Handlers @@ -60,7 +61,44 @@ \li Each Item can have unlimited Handlers \endlist - \omit TODO actual overview with snippets and stuff \endomit + \section1 Handlers Manipulating Items + + Some Handlers add interactivity simply by being declared inside an Item: + + \snippet pointerHandlers/dragHandler.qml 0 + + \section1 Handler Properties and Signals + + All Handlers have properties that can be used in bindings, and signals that + can be handled to react to input: + + \snippet pointerHandlers/hoverTapKeyButton.qml 0 + + \section1 Pointer Grab + + An important concept with Pointer Handlers is the type of grabs that they + perform. The only kind of grab an Item can take is the exclusive grab: for + example if you call \l QPointerEvent::setExclusiveGrabber(), the following + mouse moves and mouse release event will be sent only to that object. (As a + workaround to this exclusivity, see \l QQuickItem::setFiltersChildMouseEvents() + and \l QQuickItem::childMouseEventFilter().) However Pointer Handlers have + an additional mechanism available: the + \l {QPointerEvent::addPassiveGrabber()} {passive grab}. Mouse and touch + \l {QEventPoint::state()}{press} events are delivered by visiting all the + Items in top-down Z order: first each Item's child Handlers, and then the + \l {QQuickItem::event()}{Item} itself. At the time a press event is + delivered, a Handler can take either a passive or an exclusive grab + depending on its needs. If it takes a passive grab, it is guaranteed to + receive the updates and the release, even if other Items or Handlers in the + scene take any kind of grab, passive or exclusve. Some Handlers (such as + PointHandler) can work only with passive grabs; others require exclusive + grabs; and others can "lurk" with passive grabs until they detect that a + gesture is being performed, and then make the transition from passive to + exclusive grab. + + When a grab transition is requested, \l PointerHandler::grabPermissions, + \l QQuickItem::keepMouseGrab() and \l QQuickItem::keepTouchGrab() control + whether the transition will be allowed. \section1 Related Information diff --git a/src/quick/doc/src/qmltypereference.qdoc b/src/quick/doc/src/qmltypereference.qdoc index 528444cad3..65de1284a4 100644 --- a/src/quick/doc/src/qmltypereference.qdoc +++ b/src/quick/doc/src/qmltypereference.qdoc @@ -740,6 +740,73 @@ console.log(c + " " + d); // false true \li Example \row + \li translate(vector3d vector) + \li Multiplies \c this matrix4x4 by another that translates coordinates by the components + of \c vector + \li \code +var m = Qt.matrix4x4(); +m.translate(Qt.vector3d(1,2,3)); +console.log(m.toString()); +// QMatrix4x4(1, 0, 0, 1, 0, 1, 0, 2, 0, 0, 1, 3, 0, 0, 0, 1) + \endcode + + \row + \li rotate(real angle, vector3d axis) + \li Multiples \c this matrix4x4 by another that rotates coordinates through + \c angle degrees about \c axis + \li \code +var m = Qt.matrix4x4(); +m.rotate(180,vector3d(1,0,0)); +console.log(m.toString()); +// QMatrix4x4(1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 0, 0, 0, 1) + \endcode + + \row + \li scale(real factor) + \li Multiplies \c this matrix4x4 by another that scales coordinates by the given \c factor + \li \code +var m = Qt.matrix4x4(); +m.scale(2); +console.log(m.toString()); +// QMatrix4x4(2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 2, 0, 0, 0, 0, 1) + \endcode + + \row + \li scale(real x, real y, real z) + \li Multiplies \c this matrix4x4 by another that scales coordinates by the components + \c x, \c y, and \c z + \li \code +var m = Qt.matrix4x4(); +m.scale(1,2,3); +console.log(m.toString()); +// QMatrix4x4(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1) + \endcode + + \row + \li scale(vector3d vector) + \li Multiplies \c this matrix4x4 by another that scales coordinates by the components + of \c vector + \li \code +var m = Qt.matrix4x4(); +m.scale(Qt.vector3d(1,2,3)); +console.log(m.toString()); +// QMatrix4x4(1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1) + \endcode + + \row + \li lookAt(vector3d eye, vector3d center, vector3d up) + \li Multiplies \c this matrix4x4 by a viewing matrix derived from an \c eye point. + The \c center vector3d indicates the center of the view that the \c eye is looking at. + The \c up vector3d indicates which direction should be considered up with respect to + the \c eye. + \li \code +var m = Qt.matrix4x4(); +m.lookAt(Qt.vector3d(1,2,3),Qt.vector3d(1,2,0),Qt.vector3d(0,1,0)); +console.log(m.toString()); +// QMatrix4x4(1, 0, 0, -1, 0, 1, 0, -2, 0, 0, 1, -3, 0, 0, 0, 1) + \endcode + + \row \li matrix4x4 times(matrix4x4 other) \li Returns the matrix4x4 result of multiplying \c this matrix4x4 with the \c other matrix4x4 diff --git a/src/quick/handlers/qquickmultipointhandler.cpp b/src/quick/handlers/qquickmultipointhandler.cpp index f404788de4..2a9ecd341c 100644 --- a/src/quick/handlers/qquickmultipointhandler.cpp +++ b/src/quick/handlers/qquickmultipointhandler.cpp @@ -146,7 +146,7 @@ void QQuickMultiPointHandler::onActiveChanged() } } -void QQuickMultiPointHandler::onGrabChanged(QQuickPointerHandler *, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *) +void QQuickMultiPointHandler::onGrabChanged(QQuickPointerHandler *grabber, QQuickEventPoint::GrabTransition transition, QQuickEventPoint *point) { Q_D(QQuickMultiPointHandler); // If another handler or item takes over this set of points, assume it has @@ -155,6 +155,20 @@ void QQuickMultiPointHandler::onGrabChanged(QQuickPointerHandler *, QQuickEventP // (e.g. between DragHandler and PinchHandler). if (transition == QQuickEventPoint::UngrabExclusive || transition == QQuickEventPoint::CancelGrabExclusive) d->currentPoints.clear(); + if (grabber != this) + return; + switch (transition) { + case QQuickEventPoint::GrabExclusive: + case QQuickEventPoint::GrabPassive: + case QQuickEventPoint::UngrabPassive: + case QQuickEventPoint::UngrabExclusive: + case QQuickEventPoint::CancelGrabPassive: + case QQuickEventPoint::CancelGrabExclusive: + QQuickPointerHandler::onGrabChanged(grabber, transition, point); + break; + case QQuickEventPoint::OverrideGrabPassive: + return; // don't emit + } } QVector<QQuickEventPoint *> QQuickMultiPointHandler::eligiblePoints(QQuickPointerEvent *event) diff --git a/src/quick/handlers/qquickpointerhandler.cpp b/src/quick/handlers/qquickpointerhandler.cpp index 03f8d8918c..a6c18feafe 100644 --- a/src/quick/handlers/qquickpointerhandler.cpp +++ b/src/quick/handlers/qquickpointerhandler.cpp @@ -346,10 +346,16 @@ bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObjec existingPhGrabber->metaObject()->className() == metaObject()->className()) allowed = true; } else if ((d->grabPermissions & CanTakeOverFromItems)) { + allowed = true; QQuickItem * existingItemGrabber = point->grabberItem(); - if (existingItemGrabber && !((existingItemGrabber->keepMouseGrab() && point->pointerEvent()->asPointerMouseEvent()) || - (existingItemGrabber->keepTouchGrab() && point->pointerEvent()->asPointerTouchEvent()))) { - allowed = true; + QQuickWindowPrivate *winPriv = QQuickWindowPrivate::get(parentItem()->window()); + const bool isMouse = point->pointerEvent()->asPointerMouseEvent(); + const bool isTouch = point->pointerEvent()->asPointerTouchEvent(); + if (existingItemGrabber && + ((existingItemGrabber->keepMouseGrab() && + (isMouse || winPriv->isDeliveringTouchAsMouse())) || + (existingItemGrabber->keepTouchGrab() && isTouch))) { + allowed = false; // If the handler wants to steal the exclusive grab from an Item, the Item can usually veto // by having its keepMouseGrab flag set. But an exception is if that Item is a parent that // normally filters events (such as a Flickable): it needs to be possible for e.g. a @@ -358,14 +364,19 @@ bool QQuickPointerHandler::approveGrabTransition(QQuickEventPoint *point, QObjec // at first and then expects to be able to steal the grab later on. It cannot respect // Flickable's wishes in that case, because then it would never have a chance. if (existingItemGrabber->keepMouseGrab() && - !(existingItemGrabber->filtersChildMouseEvents() && existingItemGrabber->isAncestorOf(parentItem()))) { - QQuickWindowPrivate *winPriv = QQuickWindowPrivate::get(parentItem()->window()); + existingItemGrabber->filtersChildMouseEvents() && existingItemGrabber->isAncestorOf(parentItem())) { if (winPriv->isDeliveringTouchAsMouse() && point->pointId() == winPriv->touchMouseId) { - qCDebug(lcPointerHandlerGrab) << this << "wants to grab touchpoint" << point->pointId() - << "but declines to steal grab from touch-mouse grabber with keepMouseGrab=true" << existingItemGrabber; - allowed = false; + qCDebug(lcPointerHandlerGrab) << this << "steals touchpoint" << point->pointId() + << "despite parent touch-mouse grabber with keepMouseGrab=true" << existingItemGrabber; + allowed = true; } } + if (!allowed) { + qCDebug(lcPointerHandlerGrab) << this << "wants to grab point" << point->pointId() + << "but declines to steal from grabber" << existingItemGrabber + << "with keepMouseGrab=" << existingItemGrabber->keepMouseGrab() + << "keepTouchGrab=" << existingItemGrabber->keepTouchGrab(); + } } } } diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp index f3674d6fa9..2284750f15 100644 --- a/src/quick/handlers/qquicktaphandler.cpp +++ b/src/quick/handlers/qquicktaphandler.cpp @@ -209,6 +209,8 @@ void QQuickTapHandler::timerEvent(QTimerEvent *event) If the spatial constraint is violated, \l pressed transitions immediately from true to false, regardless of the time held. + The \c gesturePolicy also affects grab behavior as described below. + \value TapHandler.DragThreshold (the default value) The event point must not move significantly. If the mouse, finger or stylus moves past the system-wide drag @@ -217,11 +219,13 @@ void QQuickTapHandler::timerEvent(QTimerEvent *event) can be useful whenever TapHandler needs to cooperate with other input handlers (for example \l DragHandler) or event-handling Items (for example QtQuick Controls), because in this case TapHandler - will not take the exclusive grab, but merely a passive grab. + will not take the exclusive grab, but merely a + \l {QPointerEvent::addPassiveGrabber()}{passive grab}. \value TapHandler.WithinBounds If the event point leaves the bounds of the \c parent Item, the tap - gesture is canceled. The TapHandler will take the exclusive grab on + gesture is canceled. The TapHandler will take the + \l {QPointerEvent::setExclusiveGrabber}{exclusive grab} on press, but will release the grab as soon as the boundary constraint is no longer satisfied. @@ -232,8 +236,9 @@ void QQuickTapHandler::timerEvent(QTimerEvent *event) typical behavior for button widgets: you can cancel a click by dragging outside the button, and you can also change your mind by dragging back inside the button before release. Note that it's - necessary for TapHandler take the exclusive grab on press and retain - it until release in order to detect this gesture. + necessary for TapHandler to take the + \l {QPointerEvent::setExclusiveGrabber}{exclusive grab} on press + and retain it until release in order to detect this gesture. */ void QQuickTapHandler::setGesturePolicy(QQuickTapHandler::GesturePolicy gesturePolicy) { diff --git a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp index 55ebbe907c..1d047e3c2f 100644 --- a/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp +++ b/src/quick/items/context2d/qquickcontext2dcommandbuffer.cpp @@ -375,7 +375,10 @@ void QQuickContext2DCommandBuffer::replay(QPainter* p, QQuickContext2D::State& s } state.lineDash = pattern; QPen nPen = p->pen(); - nPen.setDashPattern(pattern); + if (count > 0) + nPen.setDashPattern(pattern); + else + nPen.setStyle(Qt::SolidLine); p->setPen(nPen); break; } diff --git a/src/quick/items/qquickdroparea.cpp b/src/quick/items/qquickdroparea.cpp index d90ee209d6..e503cd7815 100644 --- a/src/quick/items/qquickdroparea.cpp +++ b/src/quick/items/qquickdroparea.cpp @@ -91,6 +91,7 @@ QQuickDropAreaPrivate::~QQuickDropAreaPrivate() /*! \qmltype DropArea \instantiates QQuickDropArea + \inherits Item \inqmlmodule QtQuick \ingroup qtquick-input \brief For specifying drag and drop handling in an area. diff --git a/src/quick/items/qquickimage.cpp b/src/quick/items/qquickimage.cpp index 1882ec8997..04c5da6167 100644 --- a/src/quick/items/qquickimage.cpp +++ b/src/quick/items/qquickimage.cpp @@ -343,9 +343,9 @@ void QQuickImage::setFillMode(FillMode mode) } /*! - \qmlproperty real QtQuick::Image::paintedWidth \qmlproperty real QtQuick::Image::paintedHeight + \readonly These properties hold the size of the image that is actually painted. In most cases it is the same as \c width and \c height, but when using an @@ -367,6 +367,7 @@ qreal QQuickImage::paintedHeight() const /*! \qmlproperty enumeration QtQuick::Image::status + \readonly This property holds the status of image loading. It can be one of: \list @@ -404,6 +405,7 @@ qreal QQuickImage::paintedHeight() const /*! \qmlproperty real QtQuick::Image::progress + \readonly This property holds the progress of image loading, from 0.0 (nothing loaded) to 1.0 (finished). @@ -425,7 +427,7 @@ qreal QQuickImage::paintedHeight() const */ /*! - \qmlproperty QSize QtQuick::Image::sourceSize + \qmlproperty size QtQuick::Image::sourceSize This property holds the scaled width and height of the full-frame image. diff --git a/src/quick/items/qquickimagebase.cpp b/src/quick/items/qquickimagebase.cpp index 8849c2005c..d7b5709bb0 100644 --- a/src/quick/items/qquickimagebase.cpp +++ b/src/quick/items/qquickimagebase.cpp @@ -56,8 +56,8 @@ QT_BEGIN_NAMESPACE bool QQuickImageBasePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio) { // QQuickImageProvider and SVG and PDF can generate a high resolution image when - // sourceSize is set (this function is only called if it's set). - // If sourceSize is not set then the provider default size will be used, as usual. + // sourceSize is set. If sourceSize is not set then the provider default size will + // be used, as usual. bool setDevicePixelRatio = false; if (url.scheme() == QLatin1String("image")) { setDevicePixelRatio = true; @@ -418,10 +418,14 @@ void QQuickImageBase::itemChange(ItemChange change, const ItemChangeData &value) Q_D(QQuickImageBase); // If the screen DPI changed, reload image. if (change == ItemDevicePixelRatioHasChanged && value.realValue != d->devicePixelRatio) { + const auto oldDpr = d->devicePixelRatio; // ### how can we get here with !qmlEngine(this)? that implies // itemChange() on an item pending deletion, which seems strange. if (qmlEngine(this) && isComponentComplete() && d->url.isValid()) { load(); + // not changed when loading (sourceSize might not be set) + if (d->devicePixelRatio == oldDpr) + d->updateDevicePixelRatio(value.realValue); } } QQuickItem::itemChange(change, value); diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index 3df899d63d..64123c82c4 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -4790,14 +4790,24 @@ void QQuickItem::forceActiveFocus() void QQuickItem::forceActiveFocus(Qt::FocusReason reason) { + Q_D(QQuickItem); setFocus(true, reason); QQuickItem *parent = parentItem(); + QQuickItem *scope = nullptr; while (parent) { if (parent->flags() & QQuickItem::ItemIsFocusScope) { parent->setFocus(true, reason); + if (!scope) + scope = parent; } parent = parent->parentItem(); } + // In certain reparenting scenarios, d->focus might be true and the scope + // might also have focus, so that setFocus() returns early without actually + // acquiring active focus, because it thinks it already has it. In that + // case, try to set the DeliveryAgent's active focus. (QTBUG-89736). + if (scope && !d->activeFocus && d->window) + QQuickWindowPrivate::get(d->window)->setFocusInScope(scope, this, Qt::OtherFocusReason); } /*! @@ -7858,22 +7868,48 @@ bool QQuickItem::contains(const QPointF &point) const \qmlproperty QObject* QtQuick::Item::containmentMask \since 5.11 This property holds an optional mask for the Item to be used in the - QtQuick::Item::contains method. - QtQuick::Item::contains main use is currently to determine whether - an input event has landed into the item or not. + QtQuick::Item::contains() method. Its main use is currently to determine + whether a \l {QPointerEvent}{pointer event} has landed into the item or not. By default the \l contains method will return true for any point - within the Item's bounding box. \c containmentMask allows for a - more fine-grained control. For example, the developer could - define and use an AnotherItem element as containmentMask, - which has a specialized contains method, like: + within the Item's bounding box. \c containmentMask allows for + more fine-grained control. For example, if a custom C++ + QQuickItem subclass with a specialized contains() method + is used as containmentMask: \code Item { id: item; containmentMask: AnotherItem { id: anotherItem } } \endcode - \e{item}'s contains method would then return true only if - \e{anotherItem}'s contains implementation returns true. + \e{item}'s contains method would then return \c true only if + \e{anotherItem}'s contains() implementation returns \c true. + + A \l Shape can be used in this way, to make an item react to + \l {QPointerEvent}{pointer events} only within a non-rectangular region, + as illustrated in the \l {Qt Quick Examples - Shapes}{Shapes example} + (see \c tapableTriangle.qml). +*/ +/*! + \property QQuickItem::containmentMask + \since 5.11 + This property holds an optional mask to be used in the contains() method, + which is mainly used for hit-testing each \l QPointerEvent. + + By default, \l contains() will return \c true for any point + within the Item's bounding box. But any QQuickItem, or any QObject + that implements a function of the form + \code + Q_INVOKABLE bool contains(const QPointF &point) const; + \endcode + can be used as a mask, to defer hit-testing to that object. + + \note contains() is called frequently during event delivery. + Deferring hit-testing to another object slows it down somewhat. + containmentMask() can cause performance problems if that object's + contains() method is not efficient. If you implement a custom + QQuickItem subclass, you can alternatively override contains(). + + \sa contains() */ QObject *QQuickItem::containmentMask() const { diff --git a/src/quick/items/qquickstateoperations.cpp b/src/quick/items/qquickstateoperations.cpp index ddaa1979b6..a832f53e39 100644 --- a/src/quick/items/qquickstateoperations.cpp +++ b/src/quick/items/qquickstateoperations.cpp @@ -573,7 +573,7 @@ void QQuickParentChange::rewind() The AnchorChanges type is used to modify the anchors of an item in a \l State. AnchorChanges cannot be used to modify the margins on an item. For this, use - PropertyChanges intead. + PropertyChanges instead. In the following example we change the top and bottom anchors of an item using AnchorChanges, and the top and bottom anchor margins using diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index 0e7f52e816..b4b64d59cc 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -1585,7 +1585,7 @@ void QQuickTextInput::mousePressEvent(QMouseEvent *event) d->moveCursor(cursor, mark); if (d->focusOnPress && !qGuiApp->styleHints()->setFocusOnTouchRelease()) - ensureActiveFocus(); + ensureActiveFocus(Qt::MouseFocusReason); event->setAccepted(true); } @@ -1637,7 +1637,7 @@ void QQuickTextInput::mouseReleaseEvent(QMouseEvent *event) #endif if (d->focusOnPress && qGuiApp->styleHints()->setFocusOnTouchRelease()) - ensureActiveFocus(); + ensureActiveFocus(Qt::MouseFocusReason); if (!event->isAccepted()) QQuickImplicitSizeItem::mouseReleaseEvent(event); @@ -1872,10 +1872,10 @@ void QQuickTextInput::invalidateFontCaches() d->m_textLayout.engine()->resetFontEngineCache(); } -void QQuickTextInput::ensureActiveFocus() +void QQuickTextInput::ensureActiveFocus(Qt::FocusReason reason) { bool hadActiveFocus = hasActiveFocus(); - forceActiveFocus(); + forceActiveFocus(reason); #if QT_CONFIG(im) Q_D(QQuickTextInput); // re-open input panel on press if already focused diff --git a/src/quick/items/qquicktextinput_p.h b/src/quick/items/qquicktextinput_p.h index 9f7b82b168..8e97393d10 100644 --- a/src/quick/items/qquicktextinput_p.h +++ b/src/quick/items/qquicktextinput_p.h @@ -361,7 +361,7 @@ Q_SIGNALS: private: void invalidateFontCaches(); - void ensureActiveFocus(); + void ensureActiveFocus(Qt::FocusReason reason); protected: QQuickTextInput(QQuickTextInputPrivate &dd, QQuickItem *parent = nullptr); diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index c956c85091..2b9810ed57 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -450,12 +450,13 @@ void QQuickWindow::physicalDpiChanged() void QQuickWindow::handleScreenChanged(QScreen *screen) { Q_D(QQuickWindow); + // we connected to the initial screen in QQuickWindowPrivate::init, but the screen changed disconnect(d->physicalDpiChangedConnection); if (screen) { physicalDpiChanged(); // When physical DPI changes on the same screen, either the resolution or the device pixel // ratio changed. We must check what it is. Device pixel ratio does not have its own - // ...Changed() signal. + // ...Changed() signal. Reconnect, same as in QQuickWindowPrivate::init. d->physicalDpiChangedConnection = connect(screen, &QScreen::physicalDotsPerInchChanged, this, &QQuickWindow::physicalDpiChanged); } @@ -707,8 +708,13 @@ void QQuickWindowPrivate::init(QQuickWindow *c, QQuickRenderControl *control) Q_ASSERT(windowManager || renderControl); - if (QScreen *screen = q->screen()) - devicePixelRatio = screen->devicePixelRatio(); + if (QScreen *screen = q->screen()) { + devicePixelRatio = screen->devicePixelRatio(); + // if the screen changes, then QQuickWindow::handleScreenChanged disconnects + // and connects to the new screen + physicalDpiChangedConnection = QObject::connect(screen, &QScreen::physicalDotsPerInchChanged, + q, &QQuickWindow::physicalDpiChanged); + } QSGContext *sg; if (renderControl) { diff --git a/src/quick/scenegraph/qsgrenderloop.cpp b/src/quick/scenegraph/qsgrenderloop.cpp index c96129e660..ee01211545 100644 --- a/src/quick/scenegraph/qsgrenderloop.cpp +++ b/src/quick/scenegraph/qsgrenderloop.cpp @@ -413,13 +413,6 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window) qCDebug(QSG_LOG_RENDERLOOP, "cleanup without an OpenGL context"); } -#if QT_CONFIG(quick_shadereffect) - QSGRhiShaderEffectNode::cleanupMaterialTypeCache(); -#if QT_CONFIG(opengl) - QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache(); -#endif -#endif - if (d->swapchain) { if (window->handle()) { // We get here when exiting via QCoreApplication::quit() instead of @@ -432,6 +425,14 @@ void QSGGuiThreadRenderLoop::windowDestroyed(QQuickWindow *window) } d->cleanupNodesOnShutdown(); + +#if QT_CONFIG(quick_shadereffect) + QSGRhiShaderEffectNode::cleanupMaterialTypeCache(); +#if QT_CONFIG(opengl) + QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache(); +#endif +#endif + if (m_windows.size() == 0) { rc->invalidate(); d->rhi = nullptr; diff --git a/src/quick/scenegraph/qsgthreadedrenderloop.cpp b/src/quick/scenegraph/qsgthreadedrenderloop.cpp index 1c72c4dba6..d47b0d72a5 100644 --- a/src/quick/scenegraph/qsgthreadedrenderloop.cpp +++ b/src/quick/scenegraph/qsgthreadedrenderloop.cpp @@ -547,17 +547,16 @@ void QSGRenderThread::invalidateGraphics(QQuickWindow *window, bool inDestructor QQuickWindowPrivate *dd = QQuickWindowPrivate::get(window); + // The canvas nodes must be cleaned up regardless if we are in the destructor.. + if (wipeSG) { + dd->cleanupNodesOnShutdown(); #if QT_CONFIG(quick_shadereffect) - QSGRhiShaderEffectNode::cleanupMaterialTypeCache(); + QSGRhiShaderEffectNode::cleanupMaterialTypeCache(); #if QT_CONFIG(opengl) - if (current) - QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache(); + if (current) + QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache(); #endif #endif - - // The canvas nodes must be cleaned up regardless if we are in the destructor.. - if (wipeSG) { - dd->cleanupNodesOnShutdown(); } else { qCDebug(QSG_LOG_RENDERLOOP, QSG_RT_PAD, "- persistent SG, avoiding cleanup"); if (current && gl) diff --git a/src/quick/scenegraph/qsgwindowsrenderloop.cpp b/src/quick/scenegraph/qsgwindowsrenderloop.cpp index 20d7c4557f..20e127c49f 100644 --- a/src/quick/scenegraph/qsgwindowsrenderloop.cpp +++ b/src/quick/scenegraph/qsgwindowsrenderloop.cpp @@ -256,12 +256,13 @@ void QSGWindowsRenderLoop::windowDestroyed(QQuickWindow *window) if (Q_UNLIKELY(!current)) RLDEBUG("cleanup without an OpenGL context"); + d->cleanupNodesOnShutdown(); + #if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl) if (current) QQuickOpenGLShaderEffectMaterial::cleanupMaterialCache(); #endif - d->cleanupNodesOnShutdown(); if (m_windows.size() == 0) { d->context->invalidate(); delete m_gl; |