diff options
Diffstat (limited to 'src/quick')
-rw-r--r-- | src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc | 4 | ||||
-rw-r--r-- | src/quick/handlers/qquicktaphandler.cpp | 18 | ||||
-rw-r--r-- | src/quick/items/qquickitem.cpp | 37 | ||||
-rw-r--r-- | src/quick/items/qquickitem_p.h | 4 | ||||
-rw-r--r-- | src/quick/items/qquickitemview.cpp | 4 | ||||
-rw-r--r-- | src/quick/items/qquickloader.cpp | 19 | ||||
-rw-r--r-- | src/quick/items/qquickloader_p.h | 1 | ||||
-rw-r--r-- | src/quick/items/qquicktextinput.cpp | 36 | ||||
-rw-r--r-- | src/quick/items/qquickwindow.cpp | 8 | ||||
-rw-r--r-- | src/quick/items/qquickwindowmodule.cpp | 15 | ||||
-rw-r--r-- | src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp | 35 | ||||
-rw-r--r-- | src/quick/util/qquickimageprovider.cpp | 8 |
12 files changed, 120 insertions, 69 deletions
diff --git a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc index 27c8e51381..2705ca5e34 100644 --- a/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc +++ b/src/quick/doc/src/concepts/modelviewsdata/cppmodels.qdoc @@ -41,6 +41,10 @@ QObjectList or a \l QAbstractItemModel. The first three are useful for exposing simpler datasets, while QAbstractItemModel provides a more flexible solution for more complex models. +For a video tutorial that takes you through the whole process of exposing a C++ +model to QML, see the +\l {https://youtu.be/9BcAYDlpuT8}{Using C++ Models in QML Tutorial}. + \section2 QStringList-based Model A model may be a simple \l QStringList, which provides the contents of the list diff --git a/src/quick/handlers/qquicktaphandler.cpp b/src/quick/handlers/qquicktaphandler.cpp index 8313b415bf..a1b4f961ed 100644 --- a/src/quick/handlers/qquicktaphandler.cpp +++ b/src/quick/handlers/qquicktaphandler.cpp @@ -61,14 +61,20 @@ int QQuickTapHandler::m_touchMultiTapDistanceSquared(-1); TapHandler is a handler for taps on a touchscreen or clicks on a mouse. - Detection of a valid tap gesture depends on \l gesturePolicy. + Detection of a valid tap gesture depends on \l gesturePolicy. The default + value is DragThreshold, which requires the press and release to be close + together in both space and time. In this case, DragHandler is able to + function using only a passive grab, and therefore does not interfere with + event delivery to any other Items or Pointer Handlers. So the default + gesturePolicy is useful when you want to modify behavior of an existing + control or Item by adding a TapHandler with bindings and/or JavaScript + callbacks. + Note that buttons (such as QPushButton) are often implemented not to care whether the press and release occur close together: if you press the button and then change your mind, you need to drag all the way off the edge of the - button in order to cancel the click. Therefore the default - \l gesturePolicy is \c TapHandler.ReleaseWithinBounds. If you want to require - that the press and release are close together in both space and time, - set it to \c TapHandler.DragThreshold. + button in order to cancel the click. For this use case, set the + \l gesturePolicy to \c TapHandler.ReleaseWithinBounds. For multi-tap gestures (double-tap, triple-tap etc.), the distance moved must not exceed QPlatformTheme::MouseDoubleClickDistance with mouse and @@ -81,7 +87,7 @@ int QQuickTapHandler::m_touchMultiTapDistanceSquared(-1); QQuickTapHandler::QQuickTapHandler(QObject *parent) : QQuickSinglePointHandler(parent) , m_pressed(false) - , m_gesturePolicy(ReleaseWithinBounds) + , m_gesturePolicy(DragThreshold) , m_tapCount(0) , m_longPressThreshold(-1) , m_lastTapTimestamp(0.0) diff --git a/src/quick/items/qquickitem.cpp b/src/quick/items/qquickitem.cpp index f615e85e1b..18e0d30ed5 100644 --- a/src/quick/items/qquickitem.cpp +++ b/src/quick/items/qquickitem.cpp @@ -2809,7 +2809,8 @@ void QQuickItem::stackBefore(const QQuickItem *sibling) { Q_D(QQuickItem); if (!sibling || sibling == this || !d->parentItem || d->parentItem != QQuickItemPrivate::get(sibling)->parentItem) { - qWarning("QQuickItem::stackBefore: Cannot stack before %p, which must be a sibling", sibling); + qWarning().nospace() << "QQuickItem::stackBefore: Cannot stack " + << this << " before " << sibling << ", which must be a sibling"; return; } @@ -2853,7 +2854,8 @@ void QQuickItem::stackAfter(const QQuickItem *sibling) { Q_D(QQuickItem); if (!sibling || sibling == this || !d->parentItem || d->parentItem != QQuickItemPrivate::get(sibling)->parentItem) { - qWarning("QQuickItem::stackAfter: Cannot stack after %p, which must be a sibling", sibling); + qWarning().nospace() << "QQuickItem::stackAfter: Cannot stack " + << this << " after " << sibling << ", which must be a sibling"; return; } @@ -2943,6 +2945,7 @@ void QQuickItemPrivate::addChild(QQuickItem *child) if (childPrivate->subtreeHoverEnabled && !subtreeHoverEnabled) setHasHoverInChild(true); + childPrivate->recursiveRefFromEffectItem(extra.value().recursiveEffectRefCount); markSortedChildrenDirty(child); dirty(QQuickItemPrivate::ChildrenChanged); @@ -2971,6 +2974,7 @@ void QQuickItemPrivate::removeChild(QQuickItem *child) if (childPrivate->subtreeHoverEnabled && subtreeHoverEnabled) setHasHoverInChild(false); + childPrivate->recursiveRefFromEffectItem(-extra.value().recursiveEffectRefCount); markSortedChildrenDirty(child); dirty(QQuickItemPrivate::ChildrenChanged); @@ -6071,28 +6075,48 @@ void QQuickItemPrivate::removeFromDirtyList() void QQuickItemPrivate::refFromEffectItem(bool hide) { ++extra.value().effectRefCount; - if (1 == extra->effectRefCount) { + if (extra->effectRefCount == 1) { dirty(EffectReference); - if (parentItem) QQuickItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged); + if (parentItem) + QQuickItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged); } if (hide) { if (++extra->hideRefCount == 1) dirty(HideReference); } + recursiveRefFromEffectItem(1); +} + +void QQuickItemPrivate::recursiveRefFromEffectItem(int refs) +{ + Q_Q(QQuickItem); + if (!refs) + return; + extra.value().recursiveEffectRefCount += refs; + for (int ii = 0; ii < childItems.count(); ++ii) { + QQuickItem *child = childItems.at(ii); + QQuickItemPrivate::get(child)->recursiveRefFromEffectItem(refs); + } + // Polish may rely on the effect ref count so trigger one, if item is not visible + // (if visible, it will be triggered automatically). + if (!effectiveVisible && refs > 0 && extra.value().recursiveEffectRefCount == 1) // it wasn't referenced, now it's referenced + q->polish(); } void QQuickItemPrivate::derefFromEffectItem(bool unhide) { Q_ASSERT(extra->effectRefCount); --extra->effectRefCount; - if (0 == extra->effectRefCount) { + if (extra->effectRefCount == 0) { dirty(EffectReference); - if (parentItem) QQuickItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged); + if (parentItem) + QQuickItemPrivate::get(parentItem)->dirty(ChildrenStackingChanged); } if (unhide) { if (--extra->hideRefCount == 0) dirty(HideReference); } + recursiveRefFromEffectItem(-1); } void QQuickItemPrivate::setCulled(bool cull) @@ -8598,6 +8622,7 @@ QQuickItemPrivate::ExtraData::ExtraData() layer(0), #endif effectRefCount(0), hideRefCount(0), + recursiveEffectRefCount(0), opacityNode(0), clipNode(0), rootNode(0), acceptedMouseButtons(0), origin(QQuickItem::Center), transparentForPositioner(false) diff --git a/src/quick/items/qquickitem_p.h b/src/quick/items/qquickitem_p.h index 02e7424d1e..ee854bb2ac 100644 --- a/src/quick/items/qquickitem_p.h +++ b/src/quick/items/qquickitem_p.h @@ -360,8 +360,11 @@ public: #endif QPointF userTransformOriginPoint; + // these do not include child items int effectRefCount; int hideRefCount; + // updated recursively for child items as well + int recursiveEffectRefCount; QSGOpacityNode *opacityNode; QQuickDefaultClipNode *clipNode; @@ -614,6 +617,7 @@ public: // A reference from an effect item means that this item is used by the effect, so // it should insert a root node. void refFromEffectItem(bool hide); + void recursiveRefFromEffectItem(int refs); void derefFromEffectItem(bool unhide); void itemChange(QQuickItem::ItemChange, const QQuickItem::ItemChangeData &); diff --git a/src/quick/items/qquickitemview.cpp b/src/quick/items/qquickitemview.cpp index 856070634c..17a1d124ab 100644 --- a/src/quick/items/qquickitemview.cpp +++ b/src/quick/items/qquickitemview.cpp @@ -1894,6 +1894,9 @@ void QQuickItemViewPrivate::layout() inLayout = true; + // viewBounds contains bounds before any add/remove/move operation to the view + QRectF viewBounds(q->contentX(), q->contentY(), q->width(), q->height()); + if (!isValid() && !visibleItems.count()) { clear(); setPosition(contentStartOffset()); @@ -1960,7 +1963,6 @@ void QQuickItemViewPrivate::layout() prepareVisibleItemTransitions(); - QRectF viewBounds(q->contentX(), q->contentY(), q->width(), q->height()); for (QList<FxViewItem*>::Iterator it = releasePendingTransition.begin(); it != releasePendingTransition.end(); ) { FxViewItem *item = *it; diff --git a/src/quick/items/qquickloader.cpp b/src/quick/items/qquickloader.cpp index 1f2828585c..33e22c1e95 100644 --- a/src/quick/items/qquickloader.cpp +++ b/src/quick/items/qquickloader.cpp @@ -686,6 +686,13 @@ void QQuickLoaderPrivate::incubatorStateChanged(QQmlIncubator::Status status) if (status == QQmlIncubator::Ready) { object = incubator->object(); item = qmlobject_cast<QQuickItem*>(object); + if (!item) { + QQuickWindow *window = qmlobject_cast<QQuickWindow*>(object); + if (window) { + qCDebug(lcTransient) << window << "is transient for" << q->window(); + window->setTransientParent(q->window()); + } + } emit q->itemChanged(); initResize(); incubator->clear(); @@ -830,6 +837,18 @@ void QQuickLoader::componentComplete() } } +void QQuickLoader::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) +{ + if (change == ItemSceneChange) { + QQuickWindow *loadedWindow = qmlobject_cast<QQuickWindow *>(item()); + if (loadedWindow) { + qCDebug(lcTransient) << loadedWindow << "is transient for" << value.window; + loadedWindow->setTransientParent(value.window); + } + } + QQuickItem::itemChange(change, value); +} + /*! \qmlsignal QtQuick::Loader::loaded() diff --git a/src/quick/items/qquickloader_p.h b/src/quick/items/qquickloader_p.h index 27e5d1ec8b..b5137c0783 100644 --- a/src/quick/items/qquickloader_p.h +++ b/src/quick/items/qquickloader_p.h @@ -107,6 +107,7 @@ Q_SIGNALS: protected: void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; void componentComplete() override; + void itemChange(ItemChange change, const ItemChangeData &value) override; private: void setSource(const QUrl &sourceUrl, bool needsClear); diff --git a/src/quick/items/qquicktextinput.cpp b/src/quick/items/qquicktextinput.cpp index a09fc35f1c..557ff393b4 100644 --- a/src/quick/items/qquicktextinput.cpp +++ b/src/quick/items/qquicktextinput.cpp @@ -1108,7 +1108,8 @@ void QQuickTextInputPrivate::checkIsValid() Q_Q(QQuickTextInput); ValidatorState state = hasAcceptableInput(m_text); - m_validInput = state != InvalidInput; + if (!m_maskData) + m_validInput = state != InvalidInput; if (state != AcceptableInput) { if (m_acceptableInput) { m_acceptableInput = false; @@ -3561,11 +3562,15 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo #if QT_CONFIG(validator) if (m_validator) { QString textCopy = m_text; + if (m_maskData) + textCopy = maskString(0, m_text, true); int cursorCopy = m_cursor; QValidator::State state = m_validator->validate(textCopy, cursorCopy); + if (m_maskData) + textCopy = m_text; m_validInput = state != QValidator::Invalid; m_acceptableInput = state == QValidator::Acceptable; - if (m_validInput) { + if (m_validInput && !m_maskData) { if (m_text != textCopy) { internalSetText(textCopy, cursorCopy); return true; @@ -3574,31 +3579,8 @@ bool QQuickTextInputPrivate::finishChange(int validateFromState, bool update, bo } } #endif - - if (m_maskData) { - m_validInput = true; - if (m_text.length() != m_maxLength) { - m_validInput = false; - m_acceptableInput = false; - } else { - for (int i = 0; i < m_maxLength; ++i) { - if (m_maskData[i].separator) { - if (m_text.at(i) != m_maskData[i].maskChar) { - m_validInput = false; - m_acceptableInput = false; - break; - } - } else { - if (!isValidInput(m_text.at(i), m_maskData[i].maskChar)) { - m_acceptableInput = false; - if (m_text.at(i) != m_blank) - m_validInput = false; - break; - } - } - } - } - } + if (m_maskData) + checkIsValid(); if (validateFromState >= 0 && wasValidInput && !m_validInput) { if (m_transactions.count()) diff --git a/src/quick/items/qquickwindow.cpp b/src/quick/items/qquickwindow.cpp index 2e36f07fdb..6fda6ab6c6 100644 --- a/src/quick/items/qquickwindow.cpp +++ b/src/quick/items/qquickwindow.cpp @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2017 The Qt Company Ltd. +** Copyright (C) 2018 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQuick module of the Qt Toolkit. @@ -2430,8 +2430,6 @@ void QQuickWindowPrivate::deliverUpdatedTouchPoints(QQuickPointerTouchEvent *eve done = true; event->localize(receiver); handler->handlePointerEvent(event); - if (event->allPointsAccepted()) - done = true; } if (done) break; @@ -2532,8 +2530,6 @@ void QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo } if (handlersOnly) return; - if (pointerEvent->allPointsAccepted() && !pointerEvent->isReleaseEvent()) - return; // If all points are released and the item is not the grabber, it doesn't get the event. // But if at least one point is still pressed, we might be in a potential gesture-takeover scenario. @@ -2545,8 +2541,6 @@ void QQuickWindowPrivate::deliverMatchingPointsToItem(QQuickItem *item, QQuickPo auto event = pointerEvent->asPointerMouseEvent(); if (event && item->acceptedMouseButtons() & event->button()) { auto point = event->point(0); - if (point->isAccepted()) - return; // The only reason to already have a mouse grabber here is // synthetic events - flickable sends one when setPressDelay is used. auto oldMouseGrabber = q->mouseGrabberItem(); diff --git a/src/quick/items/qquickwindowmodule.cpp b/src/quick/items/qquickwindowmodule.cpp index f048f12bf9..ab3f49d5b6 100644 --- a/src/quick/items/qquickwindowmodule.cpp +++ b/src/quick/items/qquickwindowmodule.cpp @@ -123,7 +123,13 @@ void QQuickWindowQmlImpl::componentComplete() { Q_D(QQuickWindowQmlImpl); d->complete = true; - if (transientParent() && !transientParent()->isVisible()) { + QQuickItem *itemParent = qmlobject_cast<QQuickItem *>(QObject::parent()); + if (itemParent && !itemParent->window()) { + qCDebug(lcTransient) << "window" << title() << "has invisible Item parent" << itemParent << "transientParent" + << transientParent() << "declared visibility" << d->visibility << "; delaying show"; + connect(itemParent, &QQuickItem::windowChanged, this, + &QQuickWindowQmlImpl::setWindowVisibility, Qt::QueuedConnection); + } else if (transientParent() && !transientParent()->isVisible()) { connect(transientParent(), &QQuickWindow::visibleChanged, this, &QQuickWindowQmlImpl::setWindowVisibility, Qt::QueuedConnection); } else { @@ -137,9 +143,10 @@ void QQuickWindowQmlImpl::setWindowVisibility() if (transientParent() && !transientParent()->isVisible()) return; - if (sender()) { - disconnect(transientParent(), &QWindow::visibleChanged, this, - &QQuickWindowQmlImpl::setWindowVisibility); + if (QQuickItem *senderItem = qmlobject_cast<QQuickItem *>(sender())) { + disconnect(senderItem, &QQuickItem::windowChanged, this, &QQuickWindowQmlImpl::setWindowVisibility); + } else if (sender()) { + disconnect(transientParent(), &QWindow::visibleChanged, this, &QQuickWindowQmlImpl::setWindowVisibility); } // We have deferred window creation until we have the full picture of what diff --git a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp index 7531ae7604..68acfcc876 100644 --- a/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp +++ b/src/quick/scenegraph/coreapi/qsgbatchrenderer.cpp @@ -144,7 +144,7 @@ ShaderManager::Shader *ShaderManager::prepareMaterial(QSGMaterial *material) Q_QUICK_SG_PROFILE_START(QQuickProfiler::SceneGraphContextFrame); QSGMaterialShader *s = material->createShader(); - QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QOpenGLContext *ctx = context->openglContext(); QSurfaceFormat::OpenGLContextProfile profile = ctx->format().profile(); QOpenGLShaderProgram *p = s->program(); @@ -2032,7 +2032,7 @@ Renderer::ClipType Renderer::updateStencilClip(const QSGClipNode *clip) int vboSize = 0; bool useVBO = false; - QOpenGLContext *ctx = QOpenGLContext::currentContext(); + QOpenGLContext *ctx = m_context->openglContext(); QSurfaceFormat::OpenGLContextProfile profile = ctx->format().profile(); if (!ctx->isOpenGLES() && profile == QSurfaceFormat::CoreProfile) { @@ -2494,18 +2494,21 @@ void Renderer::updateLineWidth(QSGGeometry *g) if (g->drawingMode() == GL_LINE_STRIP || g->drawingMode() == GL_LINE_LOOP || g->drawingMode() == GL_LINES) glLineWidth(g->lineWidth()); #if !defined(QT_OPENGL_ES_2) - else if (!QOpenGLContext::currentContext()->isOpenGLES() && g->drawingMode() == GL_POINTS) { - QOpenGLFunctions_1_0 *gl1funcs = 0; - QOpenGLFunctions_3_2_Core *gl3funcs = 0; - if (QOpenGLContext::currentContext()->format().profile() == QSurfaceFormat::CoreProfile) - gl3funcs = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_3_2_Core>(); - else - gl1funcs = QOpenGLContext::currentContext()->versionFunctions<QOpenGLFunctions_1_0>(); - Q_ASSERT(gl1funcs || gl3funcs); - if (gl1funcs) - gl1funcs->glPointSize(g->lineWidth()); - else - gl3funcs->glPointSize(g->lineWidth()); + else { + QOpenGLContext *ctx = m_context->openglContext(); + if (!ctx->isOpenGLES() && g->drawingMode() == GL_POINTS) { + QOpenGLFunctions_1_0 *gl1funcs = 0; + QOpenGLFunctions_3_2_Core *gl3funcs = 0; + if (ctx->format().profile() == QSurfaceFormat::CoreProfile) + gl3funcs = ctx->versionFunctions<QOpenGLFunctions_3_2_Core>(); + else + gl1funcs = ctx->versionFunctions<QOpenGLFunctions_1_0>(); + Q_ASSERT(gl1funcs || gl3funcs); + if (gl1funcs) + gl1funcs->glPointSize(g->lineWidth()); + else + gl3funcs->glPointSize(g->lineWidth()); + } } #endif } @@ -2611,6 +2614,8 @@ void Renderer::deleteRemovedElements() void Renderer::render() { + Q_ASSERT(m_context->openglContext() == QOpenGLContext::currentContext()); + if (Q_UNLIKELY(debug_dump())) { qDebug("\n"); QSGNodeDumper::dump(rootNode()); @@ -3153,7 +3158,7 @@ void Renderer::visualizeOverdraw() visualizeOverdraw_helper(m_nodes.value(rootNode())); // Animate the view... - QSurface *surface = QOpenGLContext::currentContext()->surface(); + QSurface *surface = m_context->openglContext()->surface(); if (surface->surfaceClass() == QSurface::Window) if (QQuickWindow *window = qobject_cast<QQuickWindow *>(static_cast<QWindow *>(surface))) window->update(); diff --git a/src/quick/util/qquickimageprovider.cpp b/src/quick/util/qquickimageprovider.cpp index 6ee5b95dc7..a1513336a5 100644 --- a/src/quick/util/qquickimageprovider.cpp +++ b/src/quick/util/qquickimageprovider.cpp @@ -683,13 +683,15 @@ QSize QQuickImageProviderWithOptions::loadSize(const QSize &originalSize, const return res; const bool preserveAspectCropOrFit = options.preserveAspectRatioCrop() || options.preserveAspectRatioFit(); - const bool force_scale = (format == "svg" || format == "svgz"); + + if (!preserveAspectCropOrFit && (format == "svg" || format == "svgz")) + return requestedSize; qreal ratio = 0.0; - if (requestedSize.width() && (preserveAspectCropOrFit || force_scale || requestedSize.width() < originalSize.width())) { + if (requestedSize.width() && (preserveAspectCropOrFit || requestedSize.width() < originalSize.width())) { ratio = qreal(requestedSize.width()) / originalSize.width(); } - if (requestedSize.height() && (preserveAspectCropOrFit || force_scale || requestedSize.height() < originalSize.height())) { + if (requestedSize.height() && (preserveAspectCropOrFit || requestedSize.height() < originalSize.height())) { qreal hr = qreal(requestedSize.height()) / originalSize.height(); if (ratio == 0.0) ratio = hr; |