diff options
Diffstat (limited to 'src/quick/util')
26 files changed, 1344 insertions, 189 deletions
diff --git a/src/quick/util/qquickanimation.cpp b/src/quick/util/qquickanimation.cpp index 2043b50545..fe5b372da8 100644 --- a/src/quick/util/qquickanimation.cpp +++ b/src/quick/util/qquickanimation.cpp @@ -2636,7 +2636,7 @@ QQuickStateActions QQuickPropertyAnimation::createTransitionActions(QQuickStateA for (int j = 0; j < targets.count(); ++j) { QQuickStateAction myAction; QString errorMessage; - const QString propertyName = props.at(i); + const QString &propertyName = props.at(i); myAction.property = d->createProperty(targets.at(j), propertyName, this, &errorMessage); if (myAction.property.isValid()) { if (usingDefaultProperties) diff --git a/src/quick/util/qquickanimatorjob.cpp b/src/quick/util/qquickanimatorjob.cpp index 03be78ab15..a9caedec4f 100644 --- a/src/quick/util/qquickanimatorjob.cpp +++ b/src/quick/util/qquickanimatorjob.cpp @@ -207,7 +207,7 @@ void QQuickAnimatorProxyJob::setWindow(QQuickWindow *window) stop(); } else if (!m_controller && m_job) { - m_controller = QQuickWindowPrivate::get(window)->animationController; + m_controller = QQuickWindowPrivate::get(window)->animationController.get(); if (window->isSceneGraphInitialized()) readyToAnimate(); else diff --git a/src/quick/util/qquickbehavior.cpp b/src/quick/util/qquickbehavior.cpp index 76d464e7f8..ae5c481e2f 100644 --- a/src/quick/util/qquickbehavior.cpp +++ b/src/quick/util/qquickbehavior.cpp @@ -143,7 +143,7 @@ void QQuickBehavior::setAnimation(QQuickAbstractAnimation *animation) void QQuickBehaviorPrivate::animationStateChanged(QAbstractAnimationJob *, QAbstractAnimationJob::State newState,QAbstractAnimationJob::State) { - if (!blockRunningChanged) + if (!blockRunningChanged && animation) animation->notifyRunningChanged(newState == QAbstractAnimationJob::Running); } diff --git a/src/quick/util/qquickboundaryrule.cpp b/src/quick/util/qquickboundaryrule.cpp new file mode 100644 index 0000000000..3558c8bfa0 --- /dev/null +++ b/src/quick/util/qquickboundaryrule.cpp @@ -0,0 +1,574 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickboundaryrule_p.h" + +#include <qqmlcontext.h> +#include <qqmlinfo.h> +#include <private/qqmlproperty_p.h> +#include <private/qqmlengine_p.h> +#include <private/qobject_p.h> +#include <private/qquickanimation_p_p.h> +#include <QtCore/qloggingcategory.h> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcBR, "qt.quick.boundaryrule") + +class QQuickBoundaryReturnJob; +class QQuickBoundaryRulePrivate : public QObjectPrivate +{ + Q_DECLARE_PUBLIC(QQuickBoundaryRule) +public: + QQuickBoundaryRulePrivate() {} + + QQmlProperty property; + QEasingCurve easing = QEasingCurve(QEasingCurve::OutQuad); + QQuickBoundaryReturnJob *returnAnimationJob = nullptr; + // read-only properties, updated on each write() + qreal targetValue = 0; // after easing was applied + qreal peakOvershoot = 0; + qreal currentOvershoot = 0; + // settable properties + qreal minimum = 0; + qreal maximum = 0; + qreal minimumOvershoot = 0; + qreal maximumOvershoot = 0; + qreal overshootScale = 0.5; + int returnDuration = 100; + QQuickBoundaryRule::OvershootFilter overshootFilter = QQuickBoundaryRule::OvershootFilter::None; + bool enabled = true; + bool finalized = false; + + qreal easedOvershoot(qreal overshootingValue); + void resetOvershoot(); +}; + +class QQuickBoundaryReturnJob : public QAbstractAnimationJob +{ +public: + QQuickBoundaryReturnJob(QQuickBoundaryRulePrivate *br, qreal to) + : QAbstractAnimationJob() + , boundaryRule(br) + , fromValue(br->targetValue) + , toValue(to) {} + + int duration() const override { return boundaryRule->returnDuration; } + + void updateCurrentTime(int) override; + + void updateState(QAbstractAnimationJob::State newState, + QAbstractAnimationJob::State oldState) override; + + QQuickBoundaryRulePrivate *boundaryRule; + qreal fromValue; // snapshot of initial value from which we're returning + qreal toValue; // target property value to which we're returning +}; + +void QQuickBoundaryReturnJob::updateCurrentTime(int t) +{ + // The easing property tells how to behave when the property is being + // externally manipulated beyond the bounds. During returnToBounds() + // we run it in reverse, by reversing time. + qreal progress = (duration() - t) / qreal(duration()); + qreal easingValue = boundaryRule->easing.valueForProgress(progress); + qreal delta = qAbs(fromValue - toValue) * easingValue; + qreal value = (fromValue > toValue ? toValue + delta : toValue - delta); + qCDebug(lcBR) << t << "ms" << qRound(progress * 100) << "% easing" << easingValue << "->" << value; + QQmlPropertyPrivate::write(boundaryRule->property, value, + QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); +} + +void QQuickBoundaryReturnJob::updateState(QAbstractAnimationJob::State newState, QAbstractAnimationJob::State oldState) +{ + Q_UNUSED(oldState) + if (newState == QAbstractAnimationJob::Stopped) { + qCDebug(lcBR) << "return animation done"; + boundaryRule->resetOvershoot(); + boundaryRule->returnAnimationJob = nullptr; + delete this; + } +} + +/*! + \qmltype BoundaryRule + \instantiates QQuickBoundaryRule + \inqmlmodule Qt.labs.animation + \ingroup qtquick-transitions-animations + \ingroup qtquick-interceptors + \brief Defines a restriction on the range of values that can be set on a numeric property. + \since 5.14 + + A BoundaryRule defines the range of values that a particular property is + allowed to have. When an out-of-range value would otherwise be set, + it applies "resistance" via an easing curve. + + For example, the following BoundaryRule prevents DragHandler from dragging + the Rectangle too far: + + \snippet qml/boundaryRule.qml 0 + + Note that a property cannot have more than one assigned BoundaryRule. + + \sa {Animation and Transitions in Qt Quick}, {Qt Quick Examples - Animation#Behaviors}{Behavior example}, {Qt QML} +*/ + +QQuickBoundaryRule::QQuickBoundaryRule(QObject *parent) + : QObject(*(new QQuickBoundaryRulePrivate), parent) + , QQmlPropertyValueInterceptor() +{ +} + +QQuickBoundaryRule::~QQuickBoundaryRule() +{ + Q_D(QQuickBoundaryRule); + // stop any running animation and + // prevent QQuickBoundaryReturnJob::updateState() from accessing QQuickBoundaryRulePrivate + delete d->returnAnimationJob; +} + +/*! + \qmlproperty bool QtQuick::BoundaryRule::enabled + + This property holds whether the rule will be enforced when the tracked + property changes value. + + By default a BoundaryRule is enabled. +*/ +bool QQuickBoundaryRule::enabled() const +{ + Q_D(const QQuickBoundaryRule); + return d->enabled; +} + +void QQuickBoundaryRule::setEnabled(bool enabled) +{ + Q_D(QQuickBoundaryRule); + if (d->enabled == enabled) + return; + d->enabled = enabled; + emit enabledChanged(); +} + +/*! + \qmlproperty qreal QtQuick::BoundaryRule::minimum + + This property holds the smallest unconstrained value that the property is + allowed to have. If the property is set to a smaller value, it will be + constrained by \l easing and \l minimumOvershoot. + + The default is \c 0. +*/ +qreal QQuickBoundaryRule::minimum() const +{ + Q_D(const QQuickBoundaryRule); + return d->minimum; +} + +void QQuickBoundaryRule::setMinimum(qreal minimum) +{ + Q_D(QQuickBoundaryRule); + if (qFuzzyCompare(d->minimum, minimum)) + return; + d->minimum = minimum; + emit minimumChanged(); +} + +/*! + \qmlproperty qreal QtQuick::BoundaryRule::minimumOvershoot + + This property holds the amount that the property is allowed to be + less than \l minimum. Whenever the value is less than \l minimum + and greater than \c {minimum - minimumOvershoot}, it is constrained + by the \l easing curve. When the value attempts to go under + \c {minimum - minimumOvershoots} there is a hard stop. + + The default is \c 0. +*/ +qreal QQuickBoundaryRule::minimumOvershoot() const +{ + Q_D(const QQuickBoundaryRule); + return d->minimumOvershoot; +} + +void QQuickBoundaryRule::setMinimumOvershoot(qreal minimumOvershoot) +{ + Q_D(QQuickBoundaryRule); + if (qFuzzyCompare(d->minimumOvershoot, minimumOvershoot)) + return; + d->minimumOvershoot = minimumOvershoot; + emit minimumOvershootChanged(); +} + +/*! + \qmlproperty qreal QtQuick::BoundaryRule::maximum + + This property holds the largest unconstrained value that the property is + allowed to have. If the property is set to a larger value, it will be + constrained by \l easing and \l maximumOvershoot. + + The default is \c 1. +*/ +qreal QQuickBoundaryRule::maximum() const +{ + Q_D(const QQuickBoundaryRule); + return d->maximum; +} + +void QQuickBoundaryRule::setMaximum(qreal maximum) +{ + Q_D(QQuickBoundaryRule); + if (qFuzzyCompare(d->maximum, maximum)) + return; + d->maximum = maximum; + emit maximumChanged(); +} + +/*! + \qmlproperty qreal QtQuick::BoundaryRule::maximumOvershoot + + This property holds the amount that the property is allowed to be + more than \l maximum. Whenever the value is greater than \l maximum + and less than \c {maximum + maximumOvershoot}, it is constrained + by the \l easing curve. When the value attempts to exceed + \c {maximum + maximumOvershoot} there is a hard stop. + + The default is 0. +*/ +qreal QQuickBoundaryRule::maximumOvershoot() const +{ + Q_D(const QQuickBoundaryRule); + return d->maximumOvershoot; +} + +void QQuickBoundaryRule::setMaximumOvershoot(qreal maximumOvershoot) +{ + Q_D(QQuickBoundaryRule); + if (qFuzzyCompare(d->maximumOvershoot, maximumOvershoot)) + return; + d->maximumOvershoot = maximumOvershoot; + emit maximumOvershootChanged(); +} + +/*! + \qmlproperty qreal QtQuick::BoundaryRule::overshootScale + + This property holds the amount by which the \l easing is scaled during the + overshoot condition. For example if an Item is restricted from moving more + than 100 pixels beyond some limit, and the user (by means of some Input + Handler) is trying to drag it 100 pixels past the limit, if overshootScale + is set to 1, the user will succeed: the only effect of the easing curve is + to change the rate at which the item moves from overshoot 0 to overshoot + 100. But if it is set to 0.5, the BoundaryRule provides resistance such + that when the user tries to move 100 pixels, the Item will only move 50 + pixels; and the easing curve modulates the rate of movement such that it + may move in sync with the user's attempted movement at the beginning, and + then slows down, depending on the shape of the easing curve. + + The default is 0.5. +*/ +qreal QQuickBoundaryRule::overshootScale() const +{ + Q_D(const QQuickBoundaryRule); + return d->overshootScale; +} + +void QQuickBoundaryRule::setOvershootScale(qreal overshootScale) +{ + Q_D(QQuickBoundaryRule); + if (qFuzzyCompare(d->overshootScale, overshootScale)) + return; + d->overshootScale = overshootScale; + emit overshootScaleChanged(); +} + +/*! + \qmlproperty qreal QtQuick::BoundaryRule::currentOvershoot + + This property holds the amount by which the most recently set value of the + intercepted property exceeds \l maximum or is less than \l minimum. + + It is positive if the property value exceeds \l maximum, negative if the + property value is less than \l minimum, or 0 if the property value is + within both boundaries. +*/ +qreal QQuickBoundaryRule::currentOvershoot() const +{ + Q_D(const QQuickBoundaryRule); + return d->currentOvershoot; +} + +/*! + \qmlproperty qreal QtQuick::BoundaryRule::peakOvershoot + + This property holds the most-positive or most-negative value of + \l currentOvershoot that has been seen, until \l returnToBounds() is called. + + This can be useful when the intercepted property value is known to + fluctuate, and you want to find and react to the maximum amount of + overshoot rather than to the fluctuations. + + \sa overshootFilter +*/ +qreal QQuickBoundaryRule::peakOvershoot() const +{ + Q_D(const QQuickBoundaryRule); + return d->peakOvershoot; +} + +/*! + \qmlproperty enum QtQuick::BoundaryRule::overshootFilter + + This property specifies the aggregation function that will be applied to + the intercepted property value. + + If this is set to \c BoundaryRule.None (the default), the intercepted + property will hold a value whose overshoot is limited to \l currentOvershoot. + If this is set to \c BoundaryRule.Peak, the intercepted property will hold + a value whose overshoot is limited to \l peakOvershoot. +*/ +QQuickBoundaryRule::OvershootFilter QQuickBoundaryRule::overshootFilter() const +{ + Q_D(const QQuickBoundaryRule); + return d->overshootFilter; +} + +void QQuickBoundaryRule::setOvershootFilter(OvershootFilter overshootFilter) +{ + Q_D(QQuickBoundaryRule); + if (d->overshootFilter == overshootFilter) + return; + d->overshootFilter = overshootFilter; + emit overshootFilterChanged(); +} + +/*! + \qmlmethod bool QtQuick::BoundaryRule::returnToBounds + + Returns the intercepted property to a value between \l minimum and + \l maximum, such that \l currentOvershoot and \l peakOvershoot are both + zero. This will be animated if \l returnDuration is greater than zero. + + Returns true if the value needed to be adjusted, or false if it was already + within bounds. +*/ +bool QQuickBoundaryRule::returnToBounds() +{ + Q_D(QQuickBoundaryRule); + if (d->returnAnimationJob) { + qCDebug(lcBR) << "animation already in progress"; + return true; + } + if (currentOvershoot() > 0) { + if (d->returnDuration > 0) + d->returnAnimationJob = new QQuickBoundaryReturnJob(d, maximum()); + else + write(maximum()); + } else if (currentOvershoot() < 0) { + if (d->returnDuration > 0) + d->returnAnimationJob = new QQuickBoundaryReturnJob(d, minimum()); + else + write(minimum()); + } else { + return false; + } + if (d->returnAnimationJob) { + qCDebug(lcBR) << "animating from" << d->returnAnimationJob->fromValue << "to" << d->returnAnimationJob->toValue; + d->returnAnimationJob->start(); + } else { + d->resetOvershoot(); + qCDebug(lcBR) << "returned to" << d->property.read(); + } + return true; +} + +/*! + \qmlproperty qreal QtQuick::BoundaryRule::easing + + This property holds the easing curve to be applied in overshoot mode + (whenever the \l minimum or \l maximum constraint is violated, while + the value is still within the respective overshoot range). + + The default easing curve is \l QEasingCurve::OutQuad. +*/ +QEasingCurve QQuickBoundaryRule::easing() const +{ + Q_D(const QQuickBoundaryRule); + return d->easing; +} + +void QQuickBoundaryRule::setEasing(const QEasingCurve &easing) +{ + Q_D(QQuickBoundaryRule); + if (d->easing == easing) + return; + d->easing = easing; + emit easingChanged(); +} + +/*! + \qmlproperty int QtQuick::BoundaryRule::returnDuration + + This property holds the amount of time in milliseconds that + \l returnToBounds() will take to return the target property to the nearest bound. + If it is set to 0, returnToBounds() will set the property immediately + rather than creating an animation job. + + The default is 100 ms. +*/ +int QQuickBoundaryRule::returnDuration() const +{ + Q_D(const QQuickBoundaryRule); + return d->returnDuration; +} + +void QQuickBoundaryRule::setReturnDuration(int duration) +{ + Q_D(QQuickBoundaryRule); + if (d->returnDuration == duration) + return; + d->returnDuration = duration; + emit returnDurationChanged(); +} + +void QQuickBoundaryRule::write(const QVariant &value) +{ + bool conversionOk = false; + qreal rValue = value.toReal(&conversionOk); + if (!conversionOk) { + qWarning() << "BoundaryRule doesn't work with non-numeric values:" << value; + return; + } + Q_D(QQuickBoundaryRule); + bool bypass = !d->enabled || !d->finalized || QQmlEnginePrivate::designerMode(); + if (bypass) { + QQmlPropertyPrivate::write(d->property, value, + QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); + return; + } + + qmlExecuteDeferred(this); + d->targetValue = d->easedOvershoot(rValue); + QQmlPropertyPrivate::write(d->property, d->targetValue, + QQmlPropertyData::BypassInterceptor | QQmlPropertyData::DontRemoveBinding); +} + +void QQuickBoundaryRule::setTarget(const QQmlProperty &property) +{ + Q_D(QQuickBoundaryRule); + d->property = property; + + QQmlEnginePrivate *engPriv = QQmlEnginePrivate::get(qmlEngine(this)); + static int finalizedIdx = -1; + if (finalizedIdx < 0) + finalizedIdx = metaObject()->indexOfSlot("componentFinalized()"); + engPriv->registerFinalizeCallback(this, finalizedIdx); +} + +void QQuickBoundaryRule::componentFinalized() +{ + Q_D(QQuickBoundaryRule); + d->finalized = true; +} + +/*! + \internal + Given that something is trying to set the target property to \a value, + this function applies the easing curve and returns the value that the + property should actually get instead. +*/ +qreal QQuickBoundaryRulePrivate::easedOvershoot(qreal value) +{ + qreal ret = value; + Q_Q(QQuickBoundaryRule); + if (value > maximum) { + qreal overshootWas = currentOvershoot; + currentOvershoot = value - maximum; + if (!qFuzzyCompare(overshootWas, currentOvershoot)) + emit q->currentOvershootChanged(); + overshootWas = peakOvershoot; + peakOvershoot = qMax(currentOvershoot, peakOvershoot); + if (!qFuzzyCompare(overshootWas, peakOvershoot)) + emit q->peakOvershootChanged(); + ret = maximum + maximumOvershoot * easing.valueForProgress( + (overshootFilter == QQuickBoundaryRule::OvershootFilter::Peak ? peakOvershoot : currentOvershoot) + * overshootScale / maximumOvershoot); + qCDebug(lcBR).nospace() << value << " overshoots maximum " << maximum << " by " + << currentOvershoot << " (peak " << peakOvershoot << "): eased to " << ret; + } else if (value < minimum) { + qreal overshootWas = currentOvershoot; + currentOvershoot = value - minimum; + if (!qFuzzyCompare(overshootWas, currentOvershoot)) + emit q->currentOvershootChanged(); + overshootWas = peakOvershoot; + peakOvershoot = qMin(currentOvershoot, peakOvershoot); + if (!qFuzzyCompare(overshootWas, peakOvershoot)) + emit q->peakOvershootChanged(); + ret = minimum - minimumOvershoot * easing.valueForProgress( + -(overshootFilter == QQuickBoundaryRule::OvershootFilter::Peak ? peakOvershoot : currentOvershoot) + * overshootScale / minimumOvershoot); + qCDebug(lcBR).nospace() << value << " overshoots minimum " << minimum << " by " + << currentOvershoot << " (peak " << peakOvershoot << "): eased to " << ret; + } else { + resetOvershoot(); + } + return ret; +} + +/*! + \internal + Resets the currentOvershoot and peakOvershoot + properties to zero. +*/ +void QQuickBoundaryRulePrivate::resetOvershoot() +{ + Q_Q(QQuickBoundaryRule); + if (!qFuzzyCompare(peakOvershoot, 0)) { + peakOvershoot = 0; + emit q->peakOvershootChanged(); + } + if (!qFuzzyCompare(currentOvershoot, 0)) { + currentOvershoot = 0; + emit q->currentOvershootChanged(); + } +} + +QT_END_NAMESPACE + +#include "moc_qquickboundaryrule_p.cpp" diff --git a/src/quick/util/qquickboundaryrule_p.h b/src/quick/util/qquickboundaryrule_p.h new file mode 100644 index 0000000000..3325b675c5 --- /dev/null +++ b/src/quick/util/qquickboundaryrule_p.h @@ -0,0 +1,145 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** 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. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QQUICKBOUNDARYRULE_H +#define QQUICKBOUNDARYRULE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <private/qtquickglobal_p.h> + +#include <private/qqmlpropertyvalueinterceptor_p.h> +#include <qqml.h> + +QT_BEGIN_NAMESPACE + +class QQuickAbstractAnimation; +class QQuickBoundaryRulePrivate; +class Q_QUICK_PRIVATE_EXPORT QQuickBoundaryRule : public QObject, public QQmlPropertyValueInterceptor +{ + Q_OBJECT + Q_DECLARE_PRIVATE(QQuickBoundaryRule) + + Q_INTERFACES(QQmlPropertyValueInterceptor) + Q_PROPERTY(bool enabled READ enabled WRITE setEnabled NOTIFY enabledChanged) + Q_PROPERTY(qreal minimum READ minimum WRITE setMinimum NOTIFY minimumChanged) + Q_PROPERTY(qreal minimumOvershoot READ minimumOvershoot WRITE setMinimumOvershoot NOTIFY minimumOvershootChanged) + Q_PROPERTY(qreal maximum READ maximum WRITE setMaximum NOTIFY maximumChanged) + Q_PROPERTY(qreal maximumOvershoot READ maximumOvershoot WRITE setMaximumOvershoot NOTIFY maximumOvershootChanged) + Q_PROPERTY(qreal overshootScale READ overshootScale WRITE setOvershootScale NOTIFY overshootScaleChanged) + Q_PROPERTY(qreal currentOvershoot READ currentOvershoot NOTIFY currentOvershootChanged) + Q_PROPERTY(qreal peakOvershoot READ peakOvershoot NOTIFY peakOvershootChanged) + Q_PROPERTY(OvershootFilter overshootFilter READ overshootFilter WRITE setOvershootFilter NOTIFY overshootFilterChanged) + Q_PROPERTY(QEasingCurve easing READ easing WRITE setEasing NOTIFY easingChanged) + Q_PROPERTY(int returnDuration READ returnDuration WRITE setReturnDuration NOTIFY returnDurationChanged) + +public: + enum OvershootFilter { + None, + Peak + }; + Q_ENUM(OvershootFilter) + + QQuickBoundaryRule(QObject *parent=nullptr); + ~QQuickBoundaryRule(); + + void setTarget(const QQmlProperty &) override; + void write(const QVariant &value) override; + + bool enabled() const; + void setEnabled(bool enabled); + + qreal minimum() const; + void setMinimum(qreal minimum); + qreal minimumOvershoot() const; + void setMinimumOvershoot(qreal minimum); + + qreal maximum() const; + void setMaximum(qreal maximum); + qreal maximumOvershoot() const; + void setMaximumOvershoot(qreal maximum); + + qreal overshootScale() const; + void setOvershootScale(qreal scale); + + qreal currentOvershoot() const; + qreal peakOvershoot() const; + + OvershootFilter overshootFilter() const; + void setOvershootFilter(OvershootFilter overshootFilter); + + Q_INVOKABLE bool returnToBounds(); + + QEasingCurve easing() const; + void setEasing(const QEasingCurve &easing); + + int returnDuration() const; + void setReturnDuration(int duration); + +Q_SIGNALS: + void enabledChanged(); + void minimumChanged(); + void minimumOvershootChanged(); + void maximumChanged(); + void maximumOvershootChanged(); + void overshootScaleChanged(); + void currentOvershootChanged(); + void peakOvershootChanged(); + void overshootFilterChanged(); + void easingChanged(); + void returnDurationChanged(); + +private Q_SLOTS: + void componentFinalized(); +}; + +QT_END_NAMESPACE + +QML_DECLARE_TYPE(QQuickBoundaryRule) + +#endif // QQUICKBOUNDARYRULE_H diff --git a/src/quick/util/qquickglobal.cpp b/src/quick/util/qquickglobal.cpp index 5337bfd640..527274e6be 100644 --- a/src/quick/util/qquickglobal.cpp +++ b/src/quick/util/qquickglobal.cpp @@ -41,7 +41,6 @@ #include <private/qquickvaluetypes_p.h> #include <private/qquickapplication_p.h> #include <private/qqmlglobal_p.h> -#include <private/qv8engine_p.h> #include <QtGui/QGuiApplication> #include <QtGui/qdesktopservices.h> @@ -274,7 +273,7 @@ public: return QMatrix4x4(); } - static QFont fontFromObject(QQmlV4Handle object, QV4::ExecutionEngine *v4, bool *ok) + static QFont fontFromObject(const QV4::Value &object, QV4::ExecutionEngine *v4, bool *ok) { if (ok) *ok = false; @@ -373,7 +372,7 @@ public: return retn; } - static QMatrix4x4 matrix4x4FromObject(QQmlV4Handle object, QV4::ExecutionEngine *v4, bool *ok) + static QMatrix4x4 matrix4x4FromObject(const QV4::Value &object, QV4::ExecutionEngine *v4, bool *ok) { if (ok) *ok = false; @@ -639,7 +638,7 @@ public: return false; } - bool variantFromJsObject(int type, QQmlV4Handle object, QV4::ExecutionEngine *v4, QVariant *v) override + bool variantFromJsObject(int type, const QV4::Value &object, QV4::ExecutionEngine *v4, QVariant *v) override { QV4::Scope scope(v4); #ifndef QT_NO_DEBUG diff --git a/src/quick/util/qquickimageprovider_p.h b/src/quick/util/qquickimageprovider_p.h index b5baf79319..67e17010d4 100644 --- a/src/quick/util/qquickimageprovider_p.h +++ b/src/quick/util/qquickimageprovider_p.h @@ -61,7 +61,7 @@ class QQuickImageResponsePrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QQuickImageResponse) public: - bool finished = false; + QAtomicInteger<qint32> finished = false; void _q_finished() { finished = true; } }; diff --git a/src/quick/util/qquickpath.cpp b/src/quick/util/qquickpath.cpp index 60d725d650..61319c388c 100644 --- a/src/quick/util/qquickpath.cpp +++ b/src/quick/util/qquickpath.cpp @@ -60,7 +60,7 @@ QT_BEGIN_NAMESPACE This type is the base for all path types. It cannot be instantiated. - \sa Path, PathAttribute, PathPercent, PathLine, PathQuad, PathCubic, PathArc, + \sa Path, PathAttribute, PathPercent, PathLine, PathPolyline, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg */ @@ -71,7 +71,7 @@ QT_BEGIN_NAMESPACE \ingroup qtquick-animation-paths \brief Defines a path for use by \l PathView and \l Shape. - A Path is composed of one or more path segments - PathLine, PathQuad, + A Path is composed of one or more path segments - PathLine, PathPolyline, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg. The spacing of the items along the Path can be adjusted via a @@ -104,6 +104,17 @@ QT_BEGIN_NAMESPACE \li Yes \li Yes \row + \li PathPolyline + \li Yes + \li Yes + \li Yes + \li Yes + \li PathMultiLine + \li Yes + \li Yes + \li Yes + \li Yes + \row \li PathQuad \li Yes \li Yes @@ -156,7 +167,7 @@ QT_BEGIN_NAMESPACE \note Path is a non-visual type; it does not display anything on its own. To draw a path, use \l Shape. - \sa PathView, Shape, PathAttribute, PathPercent, PathLine, PathMove, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg + \sa PathView, Shape, PathAttribute, PathPercent, PathLine, PathPolyline, PathMove, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg */ QQuickPath::QQuickPath(QObject *parent) : QObject(*(new QQuickPathPrivate), parent) @@ -240,6 +251,8 @@ bool QQuickPath::isClosed() const A path can contain the following path objects: \list \li \l PathLine - a straight line to a given position. + \li \l PathPolyline - a polyline specified as a list of coordinates. + \li \l PathMultiline - a list of polylines specified as a list of lists of coordinates. \li \l PathQuad - a quadratic Bezier curve to a given position with a control point. \li \l PathCubic - a cubic Bezier curve to a given position with two control points. \li \l PathArc - an arc to a given position with a radius. @@ -407,6 +420,19 @@ void QQuickPath::processPath() emit changed(); } +inline static void scalePath(QPainterPath &path, const QSizeF &scale) +{ + const qreal xscale = scale.width(); + const qreal yscale = scale.height(); + if (xscale == 1 && yscale == 1) + return; + + for (int i = 0; i < path.elementCount(); ++i) { + const QPainterPath::Element &element = path.elementAt(i); + path.setElementPositionAt(i, element.x * xscale, element.y * yscale); + } +} + QPainterPath QQuickPath::createPath(const QPointF &startPoint, const QPointF &endPoint, const QStringList &attributes, qreal &pathLength, QList<AttributePoint> &attributePoints, bool *closed) { Q_D(QQuickPath); @@ -465,7 +491,7 @@ QPainterPath QQuickPath::createPath(const QPointF &startPoint, const QPointF &en d->_attributePoints.last().values[percentString] = 1; interpolate(d->_attributePoints.count() - 1, percentString, 1); } - + scalePath(path, d->scale); // Adjust percent qreal length = path.length(); @@ -491,7 +517,7 @@ QPainterPath QQuickPath::createPath(const QPointF &startPoint, const QPointF &en if (closed) { QPointF end = path.currentPosition(); - *closed = length > 0 && startX == end.x() && startY == end.y(); + *closed = length > 0 && startX * d->scale.width() == end.x() && startY * d->scale.height() == end.y(); } pathLength = length; @@ -525,6 +551,7 @@ QPainterPath QQuickPath::createShapePath(const QPointF &startPoint, const QPoint QPointF end = path.currentPosition(); *closed = startX == end.x() && startY == end.y(); } + scalePath(path, d->scale); // Note: Length of paths inside ShapePath is not used, so currently // length is always 0. This avoids potentially heavy path.length() @@ -570,7 +597,7 @@ void QQuickPath::gatherAttributes() attributes.insert(attribute->name()); } - d->_attributes = attributes.toList(); + d->_attributes = attributes.values(); } void QQuickPath::componentComplete() @@ -603,7 +630,7 @@ QStringList QQuickPath::attributes() const qobject_cast<QQuickPathAttribute *>(pathElement)) attrs.insert(attribute->name()); } - return attrs.toList(); + return attrs.values(); } return d->_attributes; } @@ -723,6 +750,33 @@ void QQuickPath::invalidateSequentialHistory() const d->prevBez.isValid = false; } +/*! + \qmlproperty size QtQuick::Path::scale + + This property holds the scale factor for the path. + The width and height of \a scale can be different, to + achieve anisotropic scaling. + + \note Setting this property will not affect the border width. + + \since QtQuick 2.14 +*/ +QSizeF QQuickPath::scale() const +{ + Q_D(const QQuickPath); + return d->scale; +} + +void QQuickPath::setScale(const QSizeF &scale) +{ + Q_D(QQuickPath); + if (scale == d->scale) + return; + d->scale = scale; + emit scaleChanged(); + processPath(); +} + QPointF QQuickPath::sequentialPointAt(qreal p, qreal *angle) const { Q_D(const QQuickPath); @@ -852,9 +906,28 @@ QPointF QQuickPath::backwardsPointAt(const QPainterPath &path, const qreal &path return QPointF(0,0); } -QPointF QQuickPath::pointAt(qreal p) const +/*! + \qmlmethod point Path::pointAtPercent(real t) + + Returns the point at the percentage \a t of the current path. + The argument \a t has to be between 0 and 1. + + \note Similarly to other percent methods in \l QPainterPath, + the percentage measurement is not linear with regards to the length, + if curves are present in the path. + When curves are present, the percentage argument is mapped to the \c t + parameter of the Bezier equations. + + \sa QPainterPath::pointAt + + \since QtQuick 2.14 +*/ +QPointF QQuickPath::pointAtPercent(qreal t) const { Q_D(const QQuickPath); + if (d->isShapePath) // this since ShapePath does not calculate the length at all, + return d->_path.pointAtPercent(t); // in order to be faster. + if (d->_pointCache.isEmpty()) { createPointCache(); if (d->_pointCache.isEmpty()) @@ -862,7 +935,7 @@ QPointF QQuickPath::pointAt(qreal p) const } const int segmentCount = d->_pointCache.size() - 1; - qreal idxf = p*segmentCount; + qreal idxf = t*segmentCount; int idx1 = qFloor(idxf); qreal delta = idxf - idx1; if (idx1 > segmentCount) @@ -1127,7 +1200,7 @@ void QQuickPathAttribute::setValue(qreal value) } \endqml - \sa Path, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg, PathMove + \sa Path, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg, PathMove, PathPolyline */ /*! @@ -2286,6 +2359,266 @@ void QQuickPathPercent::setValue(qreal value) emit changed(); } } + +/*! + \qmltype PathPolyline + \instantiates QQuickPathPolyline + \inqmlmodule QtQuick + \ingroup qtquick-animation-paths + \brief Defines a polyline through a list of coordinates. + \since QtQuick 2.14 + + The example below creates a triangular path consisting of four vertices + on the edge of the containing Shape's bounding box. + Through the containing shape's \l scale property, the path will be + rescaled together with its containing shape. + + \qml + PathPolyline { + id: ppl + path: [ Qt.point(0.0, 0.0), + Qt.point(1.0, 0.0), + Qt.point(0.5, 1.0), + Qt.point(0.0, 0.0) + ] + } + \endqml + + \sa Path, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg, PathMove, PathPolyline +*/ + +/*! + \qmlproperty point QtQuick::PathPolyline::start + + This read-only property contains the beginning of the polyline. +*/ + +/*! + \qmlproperty list<point> QtQuick::PathPolyline::path + + This property defines the vertices of the polyline. + + It can be a JS array of points constructed with \c Qt.point(), + a QList or QVector of QPointF, or QPolygonF. + If you are binding this to a custom property in some C++ object, + QPolygonF is the most appropriate type to use. +*/ + +QQuickPathPolyline::QQuickPathPolyline(QObject *parent) : QQuickCurve(parent) +{ +} + +QVariant QQuickPathPolyline::path() const +{ + return QVariant::fromValue(m_path); +} + +void QQuickPathPolyline::setPath(const QVariant &path) +{ + if (path.type() == QVariant::PolygonF) { + setPath(path.value<QPolygonF>()); + } else if (path.canConvert<QVector<QPointF>>()) { + setPath(path.value<QVector<QPointF>>()); + } else if (path.canConvert<QVariantList>()) { + // This handles cases other than QPolygonF or QVector<QPointF>, such as + // QList<QPointF>, QVector<QPoint>, QVariantList of QPointF, QVariantList of QPoint. + QVector<QPointF> pathList; + QVariantList vl = path.value<QVariantList>(); + // If path is a QJSValue, e.g. coming from a JS array of Qt.point() in QML, + // then path.value<QVariantList>() is inefficient. + // TODO We should be able to iterate over path.value<QSequentialIterable>() eventually + for (const QVariant &v : vl) + pathList.append(v.toPointF()); + setPath(pathList); + } else { + qWarning() << "PathPolyline: path of type" << path.type() << "not supported"; + } +} + +void QQuickPathPolyline::setPath(const QVector<QPointF> &path) +{ + if (m_path != path) { + const QPointF &oldStart = start(); + m_path = path; + const QPointF &newStart = start(); + emit pathChanged(); + if (oldStart != newStart) + emit startChanged(); + emit changed(); + } +} + +QPointF QQuickPathPolyline::start() const +{ + if (m_path.size()) { + const QPointF &p = m_path.first(); + return p; + } + return QPointF(); +} + +void QQuickPathPolyline::addToPath(QPainterPath &path, const QQuickPathData &/*data*/) +{ + if (m_path.size() < 2) + return; + + path.moveTo(m_path.first()); + for (int i = 1; i < m_path.size(); ++i) + path.lineTo(m_path.at(i)); +} + + +/*! + \qmltype PathMultiline + \instantiates QQuickPathMultiline + \inqmlmodule QtQuick + \ingroup qtquick-animation-paths + \brief Defines a set of polylines through a list of lists of coordinates. + \since QtQuick 2.14 + + This element allows to define a list of polylines at once. + Each polyline in the list will be preceded by a \l{QPainterPath::moveTo}{moveTo} + command, effectively making each polyline a separate one. + The polylines in this list are supposed to be non-intersecting with each other. + In any case, when used in conjunction with a \l ShapePath, the containing ShapePath's + \l ShapePath::fillRule applies. + That is, with the default \c OddEvenFill and non intersecting shapes, the largest shape in the list defines an area to be filled; + areas where two shapes overlap are holes; areas where three shapes overlap are filled areas inside holes, etc. + + The example below creates a high voltage symbol by adding each path + of the symbol to the list of paths. + The coordinates of the vertices are normalized, and through the containing shape's + \l scale property, the path will be rescaled together with its containing shape. + + \qml + PathMultiline { + paths: [ + [Qt.point(0.5, 0.06698), + Qt.point(1, 0.93301), + Qt.point(0, 0.93301), + Qt.point(0.5, 0.06698)], + + [Qt.point(0.5, 0.12472), + Qt.point(0.95, 0.90414), + Qt.point(0.05, 0.90414), + Qt.point(0.5, 0.12472)], + + [Qt.point(0.47131, 0.32986), + Qt.point(0.36229, 0.64789), + Qt.point(0.51492, 0.58590), + Qt.point(0.47563, 0.76014), + Qt.point(0.44950, 0.73590), + Qt.point(0.46292, 0.83392), + Qt.point(0.52162, 0.75190), + Qt.point(0.48531, 0.76230), + Qt.point(0.57529, 0.53189), + Qt.point(0.41261, 0.59189), + Qt.point(0.53001, 0.32786), + Qt.point(0.47131, 0.32986)] + ] + } + \endqml + + \sa Path, QPainterPath::setFillRule, PathPolyline, PathQuad, PathCubic, PathArc, PathAngleArc, PathCurve, PathSvg, PathMove +*/ + +/*! + \qmlproperty point QtQuick::PathMultiline::start + + This read-only property contains the beginning of the polylines. +*/ + +/*! + \qmlproperty list<list<point>> QtQuick::PathMultiline::paths + + This property defines the vertices of the polylines. + + It can be a JS array of JS arrays of points constructed with \c Qt.point(), + a QList or QVector of QPolygonF, or QVector<QVector<QPointF>>. + If you are binding this to a custom property in some C++ object, + QVector<QPolygonF> or QVector<QVector<QPointF>> is the most + appropriate type to use. +*/ + +QQuickPathMultiline::QQuickPathMultiline(QObject *parent) : QQuickCurve(parent) +{ +} + +QVariant QQuickPathMultiline::paths() const +{ + return QVariant::fromValue(m_paths); +} + +void QQuickPathMultiline::setPaths(const QVariant &paths) +{ + if (paths.canConvert<QVector<QPolygonF>>()) { + const QVector<QPolygonF> pathPolygons = paths.value<QVector<QPolygonF>>(); + QVector<QVector<QPointF>> pathVectors; + for (const QPolygonF &p : pathPolygons) + pathVectors << p; + setPaths(pathVectors); + } else if (paths.canConvert<QVector<QVector<QPointF>>>()) { + setPaths(paths.value<QVector<QVector<QPointF>>>()); + } else if (paths.canConvert<QVariantList>()) { + // This handles cases other than QVector<QPolygonF> or QVector<QVector<QPointF>>, such as + // QList<QVector<QPointF>>, QList<QList<QPointF>>, QVariantList of QVector<QPointF>, + // QVariantList of QVariantList of QPointF, QVector<QList<QPoint>> etc. + QVector<QVector<QPointF>> pathsList; + QVariantList vll = paths.value<QVariantList>(); + for (const QVariant &v : vll) { + // If we bind a QVector<QPolygonF> property directly, rather than via QVariant, + // it will come through as QJSValue that can be converted to QVariantList of QPolygonF. + if (v.canConvert<QPolygonF>()) { + pathsList.append(v.value<QPolygonF>()); + } else { + QVariantList vl = v.value<QVariantList>(); + QVector<QPointF> l; + for (const QVariant &point : vl) { + if (point.canConvert<QPointF>()) + l.append(point.toPointF()); + } + if (l.size() >= 2) + pathsList.append(l); + } + } + setPaths(pathsList); + } else { + qWarning() << "PathMultiline: paths of type" << paths.type() << "not supported"; + setPaths(QVector<QVector<QPointF>>()); + } +} + +void QQuickPathMultiline::setPaths(const QVector<QVector<QPointF>> &paths) +{ + if (m_paths != paths) { + const QPointF &oldStart = start(); + m_paths = paths; + const QPointF &newStart = start(); + emit pathsChanged(); + if (oldStart != newStart) + emit startChanged(); + emit changed(); + } +} + +QPointF QQuickPathMultiline::start() const +{ + if (m_paths.size()) + return m_paths.first().first(); + return QPointF(); +} + +void QQuickPathMultiline::addToPath(QPainterPath &path, const QQuickPathData &) +{ + if (!m_paths.size()) + return; + for (const QVector<QPointF> &p: m_paths) { + path.moveTo(p.first()); + for (int i = 1; i < p.size(); ++i) + path.lineTo(p.at(i)); + } +} + QT_END_NAMESPACE #include "moc_qquickpath_p.cpp" diff --git a/src/quick/util/qquickpath_p.h b/src/quick/util/qquickpath_p.h index 6b9a40fe6d..5987ae8f35 100644 --- a/src/quick/util/qquickpath_p.h +++ b/src/quick/util/qquickpath_p.h @@ -290,7 +290,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPathArc : public QQuickCurve Q_PROPERTY(qreal radiusY READ radiusY WRITE setRadiusY NOTIFY radiusYChanged) Q_PROPERTY(bool useLargeArc READ useLargeArc WRITE setUseLargeArc NOTIFY useLargeArcChanged) Q_PROPERTY(ArcDirection direction READ direction WRITE setDirection NOTIFY directionChanged) - Q_PROPERTY(qreal xAxisRotation READ xAxisRotation WRITE setXAxisRotation NOTIFY xAxisRotationChanged REVISION 2) + Q_PROPERTY(qreal xAxisRotation READ xAxisRotation WRITE setXAxisRotation NOTIFY xAxisRotationChanged REVISION 9) public: QQuickPathArc(QObject *parent=nullptr) @@ -321,7 +321,7 @@ Q_SIGNALS: void radiusYChanged(); void useLargeArcChanged(); void directionChanged(); - Q_REVISION(2) void xAxisRotationChanged(); + Q_REVISION(9) void xAxisRotationChanged(); private: qreal _radiusX = 0; @@ -424,6 +424,52 @@ private: qreal _value = 0; }; +class Q_QUICK_PRIVATE_EXPORT QQuickPathPolyline : public QQuickCurve +{ + Q_OBJECT + Q_PROPERTY(QPointF start READ start NOTIFY startChanged) + Q_PROPERTY(QVariant path READ path WRITE setPath NOTIFY pathChanged) +public: + QQuickPathPolyline(QObject *parent=nullptr); + + QVariant path() const; + void setPath(const QVariant &path); + void setPath(const QVector<QPointF> &path); + QPointF start() const; + void addToPath(QPainterPath &path, const QQuickPathData &data) override; + +Q_SIGNALS: + void pathChanged(); + void startChanged(); + +private: + QVector<QPointF> m_path; +}; + +class Q_QUICK_PRIVATE_EXPORT QQuickPathMultiline : public QQuickCurve +{ + Q_OBJECT + Q_PROPERTY(QPointF start READ start NOTIFY startChanged) + Q_PROPERTY(QVariant paths READ paths WRITE setPaths NOTIFY pathsChanged) +public: + QQuickPathMultiline(QObject *parent=nullptr); + + QVariant paths() const; + void setPaths(const QVariant &paths); + void setPaths(const QVector<QVector<QPointF>> &paths); + QPointF start() const; + void addToPath(QPainterPath &path, const QQuickPathData &) override; + +Q_SIGNALS: + void pathsChanged(); + void startChanged(); + +private: + QPointF absolute(const QPointF &relative) const; + + QVector<QVector<QPointF>> m_paths; +}; + struct QQuickCachedBezier { QQuickCachedBezier() {} @@ -445,6 +491,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickPath : public QObject, public QQmlParserStatu Q_PROPERTY(qreal startX READ startX WRITE setStartX NOTIFY startXChanged) Q_PROPERTY(qreal startY READ startY WRITE setStartY NOTIFY startYChanged) Q_PROPERTY(bool closed READ isClosed NOTIFY changed) + Q_PROPERTY(QSizeF scale READ scale WRITE setScale NOTIFY scaleChanged REVISION 14) Q_CLASSINFO("DefaultProperty", "pathElements") Q_INTERFACES(QQmlParserStatus) public: @@ -466,14 +513,18 @@ public: QPainterPath path() const; QStringList attributes() const; qreal attributeAt(const QString &, qreal) const; - QPointF pointAt(qreal) const; + Q_REVISION(14) Q_INVOKABLE QPointF pointAtPercent(qreal t) const; QPointF sequentialPointAt(qreal p, qreal *angle = nullptr) const; void invalidateSequentialHistory() const; + QSizeF scale() const; + void setScale(const QSizeF &scale); + Q_SIGNALS: void changed(); void startXChanged(); void startYChanged(); + Q_REVISION(14) void scaleChanged(); protected: QQuickPath(QQuickPathPrivate &dd, QObject *parent = nullptr); @@ -540,6 +591,7 @@ QML_DECLARE_TYPE(QQuickPathArc) QML_DECLARE_TYPE(QQuickPathAngleArc) QML_DECLARE_TYPE(QQuickPathSvg) QML_DECLARE_TYPE(QQuickPathPercent) +QML_DECLARE_TYPE(QQuickPathPolyline) QML_DECLARE_TYPE(QQuickPath) #endif // QQUICKPATH_H diff --git a/src/quick/util/qquickpath_p_p.h b/src/quick/util/qquickpath_p_p.h index 9735d51264..e26001ec77 100644 --- a/src/quick/util/qquickpath_p_p.h +++ b/src/quick/util/qquickpath_p_p.h @@ -84,6 +84,7 @@ public: QQmlNullableValue<qreal> startX; QQmlNullableValue<qreal> startY; qreal pathLength = 0; + QSizeF scale = QSizeF(1, 1); bool closed = false; bool componentComplete = true; bool isShapePath = false; diff --git a/src/quick/util/qquickpixmapcache.cpp b/src/quick/util/qquickpixmapcache.cpp index ced0acd9ab..56ad8ebf0b 100644 --- a/src/quick/util/qquickpixmapcache.cpp +++ b/src/quick/util/qquickpixmapcache.cpp @@ -49,7 +49,7 @@ #include <QtGui/private/qimage_p.h> #include <qpa/qplatformintegration.h> -#include <QtQuick/private/qsgtexture_p.h> +#include <QtQuick/private/qsgcontext_p.h> #include <QtQuick/private/qsgtexturereader_p.h> #include <QQuickWindow> @@ -207,7 +207,7 @@ protected: private: friend class QQuickPixmapReaderThreadObject; void processJobs(); - void processJob(QQuickPixmapReply *, const QUrl &, const QString &, QQuickImageProvider::ImageType, QQuickImageProvider *); + void processJob(QQuickPixmapReply *, const QUrl &, const QString &, QQuickImageProvider::ImageType, const QSharedPointer<QQuickImageProvider> &); #if QT_CONFIG(qml_network) void networkRequestDone(QNetworkReply *); #endif @@ -241,7 +241,7 @@ class QQuickPixmapData { public: QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QSize &s, const QQuickImageProviderOptions &po, const QString &e) - : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Error), + : refCount(1), frameCount(1), frame(0), inCache(false), pixmapStatus(QQuickPixmap::Error), url(u), errorString(e), requestSize(s), providerOptions(po), appliedTransform(QQuickImageProviderOptions::UsePluginDefaultTransform), textureFactory(nullptr), reply(nullptr), prevUnreferenced(nullptr), @@ -250,8 +250,8 @@ public: declarativePixmaps.insert(pixmap); } - QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform) - : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Loading), + QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform, int frame=0, int frameCount=1) + : refCount(1), frameCount(frameCount), frame(frame), inCache(false), pixmapStatus(QQuickPixmap::Loading), url(u), requestSize(r), providerOptions(po), appliedTransform(aTransform), textureFactory(nullptr), reply(nullptr), prevUnreferenced(nullptr), prevUnreferencedPtr(nullptr), @@ -261,8 +261,8 @@ public: } QQuickPixmapData(QQuickPixmap *pixmap, const QUrl &u, QQuickTextureFactory *texture, - const QSize &s, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform) - : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Ready), + const QSize &s, const QSize &r, const QQuickImageProviderOptions &po, QQuickImageProviderOptions::AutoTransform aTransform, int frame=0, int frameCount=1) + : refCount(1), frameCount(frameCount), frame(frame), inCache(false), pixmapStatus(QQuickPixmap::Ready), url(u), implicitSize(s), requestSize(r), providerOptions(po), appliedTransform(aTransform), textureFactory(texture), reply(nullptr), prevUnreferenced(nullptr), @@ -272,7 +272,7 @@ public: } QQuickPixmapData(QQuickPixmap *pixmap, QQuickTextureFactory *texture) - : refCount(1), inCache(false), pixmapStatus(QQuickPixmap::Ready), + : refCount(1), frameCount(1), frame(0), inCache(false), pixmapStatus(QQuickPixmap::Ready), appliedTransform(QQuickImageProviderOptions::UsePluginDefaultTransform), textureFactory(texture), reply(nullptr), prevUnreferenced(nullptr), prevUnreferencedPtr(nullptr), nextUnreferenced(nullptr) @@ -299,6 +299,8 @@ public: void removeFromCache(); uint refCount; + int frameCount; + int frame; bool inCache:1; @@ -396,9 +398,9 @@ static void maybeRemoveAlpha(QImage *image) } } -static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize, +static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *errorString, QSize *impsize, int *frameCount, const QSize &requestSize, const QQuickImageProviderOptions &providerOptions, - QQuickImageProviderOptions::AutoTransform *appliedTransform = nullptr) + QQuickImageProviderOptions::AutoTransform *appliedTransform = nullptr, int frame = 0) { QImageReader imgio(dev); if (providerOptions.autoTransform() != QQuickImageProviderOptions::UsePluginDefaultTransform) @@ -406,6 +408,12 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e else if (appliedTransform) *appliedTransform = imgio.autoTransform() ? QQuickImageProviderOptions::ApplyTransform : QQuickImageProviderOptions::DoNotApplyTransform; + if (frame < imgio.imageCount()) + imgio.jumpToImage(frame); + + if (frameCount) + *frameCount = imgio.imageCount(); + QSize scSize = QQuickImageProviderWithOptions::loadSize(imgio.size(), requestSize, imgio.format(), providerOptions); if (scSize.isValid()) imgio.setScaledSize(scSize); @@ -558,9 +566,12 @@ void QQuickPixmapReader::networkRequestDone(QNetworkReply *reply) QByteArray all = reply->readAll(); QBuffer buff(&all); buff.open(QIODevice::ReadOnly); - if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, job->requestSize, job->providerOptions)) + int frameCount; + if (!readImage(reply->url(), &buff, &image, &errorString, &readSize, &frameCount, job->requestSize, job->providerOptions, nullptr, job->data->frame)) error = QQuickPixmapReply::Decoding; - } + else + job->data->frameCount = frameCount; + } // send completion event to the QQuickPixmapReply mutex.lock(); if (!cancelled.contains(job)) @@ -683,10 +694,11 @@ void QQuickPixmapReader::processJobs() const QUrl url = job->url; QString localFile; QQuickImageProvider::ImageType imageType = QQuickImageProvider::Invalid; - QQuickImageProvider *provider = nullptr; + QSharedPointer<QQuickImageProvider> provider; if (url.scheme() == QLatin1String("image")) { - provider = static_cast<QQuickImageProvider *>(engine->imageProvider(imageProviderId(url))); + QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine); + provider = enginePrivate->imageProvider(imageProviderId(url)).staticCast<QQuickImageProvider>(); if (provider) imageType = provider->imageType(); @@ -721,7 +733,7 @@ void QQuickPixmapReader::processJobs() } void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &url, const QString &localFile, - QQuickImageProvider::ImageType imageType, QQuickImageProvider *provider) + QQuickImageProvider::ImageType imageType, const QSharedPointer<QQuickImageProvider> &provider) { // fetch if (url.scheme() == QLatin1String("image")) { @@ -737,7 +749,8 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u return; } - QQuickImageProviderWithOptions *providerV2 = QQuickImageProviderWithOptions::checkedCast(provider); + // This is safe because we ensure that provider does outlive providerV2 and it does not escape the function + QQuickImageProviderWithOptions *providerV2 = QQuickImageProviderWithOptions::checkedCast(provider.get()); switch (imageType) { case QQuickImageProvider::Invalid: @@ -817,17 +830,24 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u if (providerV2) { response = providerV2->requestImageResponse(imageId(url), runningJob->requestSize, runningJob->providerOptions); } else { - QQuickAsyncImageProvider *asyncProvider = static_cast<QQuickAsyncImageProvider*>(provider); + QQuickAsyncImageProvider *asyncProvider = static_cast<QQuickAsyncImageProvider*>(provider.get()); response = asyncProvider->requestImageResponse(imageId(url), runningJob->requestSize); } + { + QObject::connect(response, SIGNAL(finished()), threadObject, SLOT(asyncResponseFinished())); + // as the response object can outlive the provider QSharedPointer, we have to extend the pointee's lifetime by that of the response + // we do this by capturing a copy of the QSharedPointer in a lambda, and dropping it once the lambda has been called + auto provider_copy = provider; // capturing provider would capture it as a const reference, and copy capture with initializer is only available in C++14 + QObject::connect(response, &QQuickImageResponse::destroyed, response, [provider_copy]() { + // provider_copy will be deleted when the connection gets deleted + }); + } // Might be that the async provider was so quick it emitted the signal before we // could connect to it. - if (static_cast<QQuickImageResponsePrivate*>(QObjectPrivate::get(response))->finished) { + if (static_cast<QQuickImageResponsePrivate*>(QObjectPrivate::get(response))->finished.loadAcquire()) { QMetaObject::invokeMethod(threadObject, "asyncResponseFinished", Qt::QueuedConnection, Q_ARG(QQuickImageResponse*, response)); - } else { - QObject::connect(response, SIGNAL(finished()), threadObject, SLOT(asyncResponseFinished())); } asyncResponses.insert(response, runningJob); @@ -861,10 +881,13 @@ void QQuickPixmapReader::processJob(QQuickPixmapReply *runningJob, const QUrl &u mutex.unlock(); return; } else { - if (!readImage(url, &f, &image, &errorStr, &readSize, runningJob->requestSize, runningJob->providerOptions)) { + int frameCount; + if (!readImage(url, &f, &image, &errorStr, &readSize, &frameCount, runningJob->requestSize, runningJob->providerOptions, nullptr, runningJob->data->frame)) { errorCode = QQuickPixmapReply::Loading; if (f.fileName() != localFile) errorStr += QString::fromLatin1(" (%1)").arg(f.fileName()); + } else if (runningJob->data) { + runningJob->data->frameCount = frameCount; } } } else { @@ -973,17 +996,18 @@ class QQuickPixmapKey public: const QUrl *url; const QSize *size; + int frame; QQuickImageProviderOptions options; }; inline bool operator==(const QQuickPixmapKey &lhs, const QQuickPixmapKey &rhs) { - return *lhs.size == *rhs.size && *lhs.url == *rhs.url && lhs.options == rhs.options; + return *lhs.size == *rhs.size && *lhs.url == *rhs.url && lhs.options == rhs.options && lhs.frame == rhs.frame; } inline uint qHash(const QQuickPixmapKey &key) { - return qHash(*key.url) ^ (key.size->width()*7) ^ (key.size->height()*17) ^ (key.options.autoTransform() * 0x5c5c5c5c); + return qHash(*key.url) ^ (key.size->width()*7) ^ (key.size->height()*17) ^ (key.frame*23) ^ (key.options.autoTransform() * 0x5c5c5c5c); } class QQuickPixmapStore : public QObject @@ -1245,7 +1269,7 @@ void QQuickPixmapData::release() void QQuickPixmapData::addToCache() { if (!inCache) { - QQuickPixmapKey key = { &url, &requestSize, providerOptions }; + QQuickPixmapKey key = { &url, &requestSize, frame, providerOptions }; pixmapStore()->m_cache.insert(key, this); inCache = true; PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>( @@ -1256,7 +1280,7 @@ void QQuickPixmapData::addToCache() void QQuickPixmapData::removeFromCache() { if (inCache) { - QQuickPixmapKey key = { &url, &requestSize, providerOptions }; + QQuickPixmapKey key = { &url, &requestSize, frame, providerOptions }; pixmapStore()->m_cache.remove(key); inCache = false; PIXMAP_PROFILE(pixmapCountChanged<QQuickProfiler::PixmapCacheCountChanged>( @@ -1264,14 +1288,16 @@ void QQuickPixmapData::removeFromCache() } } -static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, QQmlEngine *engine, const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &providerOptions, bool *ok) +static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, QQmlEngine *engine, const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &providerOptions, int frame, bool *ok) { if (url.scheme() == QLatin1String("image")) { QSize readSize; QQuickImageProvider::ImageType imageType = QQuickImageProvider::Invalid; - QQuickImageProvider *provider = static_cast<QQuickImageProvider *>(engine->imageProvider(imageProviderId(url))); - QQuickImageProviderWithOptions *providerV2 = QQuickImageProviderWithOptions::checkedCast(provider); + QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine); + QSharedPointer<QQuickImageProvider> provider = enginePrivate->imageProvider(imageProviderId(url)).dynamicCast<QQuickImageProvider>(); + // it is safe to use get() as providerV2 does not escape and is outlived by provider + QQuickImageProviderWithOptions *providerV2 = QQuickImageProviderWithOptions::checkedCast(provider.get()); if (provider) imageType = provider->imageType(); @@ -1285,7 +1311,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q : provider->requestTexture(imageId(url), &readSize, requestSize); if (texture) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, texture, readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); + return new QQuickPixmapData(declarativePixmap, url, texture, readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame); } break; } @@ -1296,7 +1322,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q : provider->requestImage(imageId(url), &readSize, requestSize); if (!image.isNull()) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); + return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame); } break; } @@ -1306,7 +1332,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q : provider->requestPixmap(imageId(url), &readSize, requestSize); if (!pixmap.isNull()) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); + return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(pixmap.toImage()), readSize, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame); } break; } @@ -1336,7 +1362,7 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q QQuickTextureFactory *factory = texReader.read(); if (factory) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, factory, factory->textureSize(), requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); + return new QQuickPixmapData(declarativePixmap, url, factory, factory->textureSize(), requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame); } else { errorString = QQuickPixmap::tr("Error decoding: %1").arg(url.toString()); if (f.fileName() != localFile) @@ -1345,9 +1371,10 @@ static QQuickPixmapData* createPixmapDataSync(QQuickPixmap *declarativePixmap, Q } else { QImage image; QQuickImageProviderOptions::AutoTransform appliedTransform = providerOptions.autoTransform(); - if (readImage(url, &f, &image, &errorString, &readSize, requestSize, providerOptions, &appliedTransform)) { + int frameCount; + if (readImage(url, &f, &image, &errorString, &readSize, &frameCount, requestSize, providerOptions, &appliedTransform, frame)) { *ok = true; - return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, appliedTransform); + return new QQuickPixmapData(declarativePixmap, url, QQuickTextureFactory::textureFactoryForImage(image), readSize, requestSize, providerOptions, appliedTransform, frame, frameCount); } else if (f.fileName() != localFile) { errorString += QString::fromLatin1(" (%1)").arg(f.fileName()); } @@ -1465,6 +1492,13 @@ QQuickImageProviderOptions::AutoTransform QQuickPixmap::autoTransform() const return QQuickImageProviderOptions::UsePluginDefaultTransform; } +int QQuickPixmap::frameCount() const +{ + if (d) + return d->frameCount; + return 0; +} + QQuickTextureFactory *QQuickPixmap::textureFactory() const { if (d) @@ -1543,7 +1577,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques load(engine, url, requestSize, options, QQuickImageProviderOptions()); } -void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &requestSize, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions) +void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &requestSize, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions, int frame, int frameCount) { if (d) { d->declarativePixmaps.remove(this); @@ -1551,7 +1585,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques d = nullptr; } - QQuickPixmapKey key = { &url, &requestSize, providerOptions }; + QQuickPixmapKey key = { &url, &requestSize, frame, providerOptions }; QQuickPixmapStore *store = pixmapStore(); QHash<QQuickPixmapKey, QQuickPixmapData *>::Iterator iter = store->m_cache.end(); @@ -1563,14 +1597,15 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques QSize dummy; if (requestSize != dummy) qWarning() << "Ignoring sourceSize request for image url that came from grabToImage. Use the targetSize parameter of the grabToImage() function instead."; - const QQuickPixmapKey grabberKey = { &url, &dummy, QQuickImageProviderOptions() }; + const QQuickPixmapKey grabberKey = { &url, &dummy, 0, QQuickImageProviderOptions() }; iter = store->m_cache.find(grabberKey); } else if (options & QQuickPixmap::Cache) iter = store->m_cache.find(key); if (iter == store->m_cache.end()) { if (url.scheme() == QLatin1String("image")) { - if (QQuickImageProvider *provider = static_cast<QQuickImageProvider *>(engine->imageProvider(imageProviderId(url)))) { + QQmlEnginePrivate *enginePrivate = QQmlEnginePrivate::get(engine); + if (auto provider = enginePrivate->imageProvider(imageProviderId(url)).staticCast<QQuickImageProvider>()) { const bool threadedPixmaps = QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::ThreadedPixmaps); if (!threadedPixmaps && provider->imageType() == QQuickImageProvider::Pixmap) { // pixmaps can only be loaded synchronously @@ -1584,7 +1619,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques if (!(options & QQuickPixmap::Asynchronous)) { bool ok = false; PIXMAP_PROFILE(pixmapStateChanged<QQuickProfiler::PixmapLoadingStarted>(url)); - d = createPixmapDataSync(this, engine, url, requestSize, providerOptions, &ok); + d = createPixmapDataSync(this, engine, url, requestSize, providerOptions, frame, &ok); if (ok) { PIXMAP_PROFILE(pixmapLoadingFinished(url, QSize(width(), height()))); if (options & QQuickPixmap::Cache) @@ -1601,7 +1636,7 @@ void QQuickPixmap::load(QQmlEngine *engine, const QUrl &url, const QSize &reques return; - d = new QQuickPixmapData(this, url, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform); + d = new QQuickPixmapData(this, url, requestSize, providerOptions, QQuickImageProviderOptions::UsePluginDefaultTransform, frame, frameCount); if (options & QQuickPixmap::Cache) d->addToCache(); @@ -1635,9 +1670,9 @@ void QQuickPixmap::clear(QObject *obj) } } -bool QQuickPixmap::isCached(const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &options) +bool QQuickPixmap::isCached(const QUrl &url, const QSize &requestSize, const int frame, const QQuickImageProviderOptions &options) { - QQuickPixmapKey key = { &url, &requestSize, options }; + QQuickPixmapKey key = { &url, &requestSize, frame, options }; QQuickPixmapStore *store = pixmapStore(); return store->m_cache.contains(key); diff --git a/src/quick/util/qquickpixmapcache_p.h b/src/quick/util/qquickpixmapcache_p.h index 91fb1ed3bb..ab5d391fa2 100644 --- a/src/quick/util/qquickpixmapcache_p.h +++ b/src/quick/util/qquickpixmapcache_p.h @@ -150,6 +150,7 @@ public: const QSize &implicitSize() const; const QSize &requestSize() const; QQuickImageProviderOptions::AutoTransform autoTransform() const; + int frameCount() const; QImage image() const; void setImage(const QImage &); void setPixmap(const QQuickPixmap &other); @@ -164,7 +165,7 @@ public: void load(QQmlEngine *, const QUrl &, QQuickPixmap::Options options); void load(QQmlEngine *, const QUrl &, const QSize &); void load(QQmlEngine *, const QUrl &, const QSize &, QQuickPixmap::Options options); - void load(QQmlEngine *, const QUrl &, const QSize &, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions); + void load(QQmlEngine *, const QUrl &, const QSize &, QQuickPixmap::Options options, const QQuickImageProviderOptions &providerOptions, int frame = 0, int frameCount = 1); void clear(); void clear(QObject *); @@ -175,7 +176,7 @@ public: bool connectDownloadProgress(QObject *, int); static void purgeCache(); - static bool isCached(const QUrl &url, const QSize &requestSize, const QQuickImageProviderOptions &options); + static bool isCached(const QUrl &url, const QSize &requestSize, const int frame, const QQuickImageProviderOptions &options); static const QLatin1String itemGrabberScheme; diff --git a/src/quick/util/qquickpropertychanges.cpp b/src/quick/util/qquickpropertychanges.cpp index d739c8a017..1cb30f5a8d 100644 --- a/src/quick/util/qquickpropertychanges.cpp +++ b/src/quick/util/qquickpropertychanges.cpp @@ -51,6 +51,7 @@ #include <private/qqmlcontext_p.h> #include <private/qquickstate_p_p.h> #include <private/qqmlboundsignal_p.h> +#include <private/qv4qmlcontext_p.h> #include <QtCore/qdebug.h> @@ -201,14 +202,14 @@ public: QPointer<QObject> object; QList<const QV4::CompiledData::Binding *> bindings; - QQmlRefPointer<QV4::CompiledData::CompilationUnit> compilationUnit; + QQmlRefPointer<QV4::ExecutableCompilationUnit> compilationUnit; bool decoded : 1; bool restore : 1; bool isExplicit : 1; void decode(); - void decodeBinding(const QString &propertyPrefix, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &qmlUnit, const QV4::CompiledData::Binding *binding); + void decodeBinding(const QString &propertyPrefix, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &qmlUnit, const QV4::CompiledData::Binding *binding); class ExpressionChange { public: @@ -236,7 +237,7 @@ public: QQmlProperty property(const QString &); }; -void QQuickPropertyChangesParser::verifyList(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding) +void QQuickPropertyChangesParser::verifyList(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding) { if (binding->type == QV4::CompiledData::Binding::Type_Object) { error(compilationUnit->objectAt(binding->value.objectIndex), QQuickPropertyChanges::tr("PropertyChanges does not support creating state-specific objects.")); @@ -266,7 +267,7 @@ void QQuickPropertyChangesPrivate::decode() decoded = true; } -void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding) +void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding) { Q_Q(QQuickPropertyChanges); @@ -314,7 +315,7 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, QQmlBinding::Identifier id = QQmlBinding::Invalid; if (!binding->isTranslationBinding()) { - expression = binding->valueAsString(compilationUnit.data()); + expression = compilationUnit->bindingValueAsString(binding); id = binding->value.compiledScriptIndex; } expressions << ExpressionChange(propertyName, binding, id, expression, url, line, column); @@ -328,10 +329,10 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, case QV4::CompiledData::Binding::Type_TranslationById: Q_UNREACHABLE(); case QV4::CompiledData::Binding::Type_String: - var = binding->valueAsString(compilationUnit.data()); + var = compilationUnit->bindingValueAsString(binding); break; case QV4::CompiledData::Binding::Type_Number: - var = binding->valueAsNumber(compilationUnit->constants); + var = compilationUnit->bindingValueAsNumber(binding); break; case QV4::CompiledData::Binding::Type_Boolean: var = binding->valueAsBoolean(); @@ -346,13 +347,13 @@ void QQuickPropertyChangesPrivate::decodeBinding(const QString &propertyPrefix, properties << qMakePair(propertyName, var); } -void QQuickPropertyChangesParser::verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props) +void QQuickPropertyChangesParser::verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props) { for (int ii = 0; ii < props.count(); ++ii) verifyList(compilationUnit, props.at(ii)); } -void QQuickPropertyChangesParser::applyBindings(QObject *obj, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) +void QQuickPropertyChangesParser::applyBindings(QObject *obj, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) { QQuickPropertyChangesPrivate *p = static_cast<QQuickPropertyChangesPrivate *>(QObjectPrivate::get(obj)); @@ -539,9 +540,7 @@ bool QQuickPropertyChanges::containsValue(const QString &name) const Q_D(const QQuickPropertyChanges); typedef QPair<QString, QVariant> PropertyEntry; - QListIterator<PropertyEntry> propertyIterator(d->properties); - while (propertyIterator.hasNext()) { - const PropertyEntry &entry = propertyIterator.next(); + for (const PropertyEntry &entry : d->properties) { if (entry.first == name) { return true; } @@ -555,9 +554,7 @@ bool QQuickPropertyChanges::containsExpression(const QString &name) const Q_D(const QQuickPropertyChanges); typedef QQuickPropertyChangesPrivate::ExpressionChange ExpressionEntry; - QListIterator<ExpressionEntry> expressionIterator(d->expressions); - while (expressionIterator.hasNext()) { - const ExpressionEntry &entry = expressionIterator.next(); + for (const ExpressionEntry &entry : d->expressions) { if (entry.name == name) { return true; } @@ -575,13 +572,10 @@ void QQuickPropertyChanges::changeValue(const QString &name, const QVariant &val { Q_D(QQuickPropertyChanges); typedef QPair<QString, QVariant> PropertyEntry; - typedef QQuickPropertyChangesPrivate::ExpressionChange ExpressionEntry; - QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions); - while (expressionIterator.hasNext()) { - const ExpressionEntry &entry = expressionIterator.next(); - if (entry.name == name) { - expressionIterator.remove(); + for (auto it = d->expressions.begin(), end = d->expressions.end(); it != end; ++it) { + if (it->name == name) { + d->expressions.erase(it); if (state() && state()->isStateActive()) { QQmlPropertyPrivate::removeBinding(d->property(name)); d->property(name).write(value); @@ -592,11 +586,9 @@ void QQuickPropertyChanges::changeValue(const QString &name, const QVariant &val } } - QMutableListIterator<PropertyEntry> propertyIterator(d->properties); - while (propertyIterator.hasNext()) { - PropertyEntry &entry = propertyIterator.next(); - if (entry.first == name) { - entry.second = value; + for (auto it = d->properties.begin(), end = d->properties.end(); it != end; ++it) { + if (it->first == name) { + it->second = value; if (state() && state()->isStateActive()) d->property(name).write(value); return; @@ -611,7 +603,7 @@ void QQuickPropertyChanges::changeValue(const QString &name, const QVariant &val action.specifiedProperty = name; action.toValue = value; - propertyIterator.insert(PropertyEntry(name, value)); + d->properties.append(PropertyEntry(name, value)); if (state() && state()->isStateActive()) { state()->addEntryToRevertList(action); QQmlAbstractBinding *oldBinding = QQmlPropertyPrivate::binding(action.property); @@ -624,26 +616,21 @@ void QQuickPropertyChanges::changeValue(const QString &name, const QVariant &val void QQuickPropertyChanges::changeExpression(const QString &name, const QString &expression) { Q_D(QQuickPropertyChanges); - typedef QPair<QString, QVariant> PropertyEntry; typedef QQuickPropertyChangesPrivate::ExpressionChange ExpressionEntry; bool hadValue = false; - QMutableListIterator<PropertyEntry> propertyIterator(d->properties); - while (propertyIterator.hasNext()) { - PropertyEntry &entry = propertyIterator.next(); - if (entry.first == name) { - propertyIterator.remove(); + for (auto it = d->properties.begin(), end = d->properties.end(); it != end; ++it) { + if (it->first == name) { + d->properties.erase(it); hadValue = true; break; } } - QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions); - while (expressionIterator.hasNext()) { - ExpressionEntry &entry = expressionIterator.next(); - if (entry.name == name) { - entry.expression = expression; + for (auto it = d->expressions.begin(), end = d->expressions.end(); it != end; ++it) { + if (it->name == name) { + it->expression = expression; if (state() && state()->isStateActive()) { auto prop = d->property(name); QQmlBinding *newBinding = QQmlBinding::create( @@ -657,7 +644,7 @@ void QQuickPropertyChanges::changeExpression(const QString &name, const QString } // adding a new expression. - expressionIterator.insert(ExpressionEntry(name, nullptr, QQmlBinding::Invalid, expression, QUrl(), -1, -1)); + d->expressions.append(ExpressionEntry(name, nullptr, QQmlBinding::Invalid, expression, QUrl(), -1, -1)); if (state() && state()->isStateActive()) { if (hadValue) { @@ -713,17 +700,13 @@ QVariant QQuickPropertyChanges::property(const QString &name) const typedef QPair<QString, QVariant> PropertyEntry; typedef QQuickPropertyChangesPrivate::ExpressionChange ExpressionEntry; - QListIterator<PropertyEntry> propertyIterator(d->properties); - while (propertyIterator.hasNext()) { - const PropertyEntry &entry = propertyIterator.next(); + for (const PropertyEntry &entry : d->properties) { if (entry.first == name) { return entry.second; } } - QListIterator<ExpressionEntry> expressionIterator(d->expressions); - while (expressionIterator.hasNext()) { - const ExpressionEntry &entry = expressionIterator.next(); + for (const ExpressionEntry &entry : d->expressions) { if (entry.name == name) { return QVariant(entry.expression); } @@ -735,24 +718,18 @@ QVariant QQuickPropertyChanges::property(const QString &name) const void QQuickPropertyChanges::removeProperty(const QString &name) { Q_D(QQuickPropertyChanges); - typedef QPair<QString, QVariant> PropertyEntry; - typedef QQuickPropertyChangesPrivate::ExpressionChange ExpressionEntry; - QMutableListIterator<ExpressionEntry> expressionIterator(d->expressions); - while (expressionIterator.hasNext()) { - const ExpressionEntry &entry = expressionIterator.next(); - if (entry.name == name) { - expressionIterator.remove(); + for (auto it = d->expressions.begin(), end = d->expressions.end(); it != end; ++it) { + if (it->name == name) { + d->expressions.erase(it); state()->removeEntryFromRevertList(object(), name); return; } } - QMutableListIterator<PropertyEntry> propertyIterator(d->properties); - while (propertyIterator.hasNext()) { - const PropertyEntry &entry = propertyIterator.next(); - if (entry.first == name) { - propertyIterator.remove(); + for (auto it = d->properties.begin(), end = d->properties.end(); it != end; ++it) { + if (it->first == name) { + d->properties.erase(it); state()->removeEntryFromRevertList(object(), name); return; } @@ -764,9 +741,7 @@ QVariant QQuickPropertyChanges::value(const QString &name) const Q_D(const QQuickPropertyChanges); typedef QPair<QString, QVariant> PropertyEntry; - QListIterator<PropertyEntry> propertyIterator(d->properties); - while (propertyIterator.hasNext()) { - const PropertyEntry &entry = propertyIterator.next(); + for (const PropertyEntry &entry : d->properties) { if (entry.first == name) { return entry.second; } @@ -780,9 +755,7 @@ QString QQuickPropertyChanges::expression(const QString &name) const Q_D(const QQuickPropertyChanges); typedef QQuickPropertyChangesPrivate::ExpressionChange ExpressionEntry; - QListIterator<ExpressionEntry> expressionIterator(d->expressions); - while (expressionIterator.hasNext()) { - const ExpressionEntry &entry = expressionIterator.next(); + for (const ExpressionEntry &entry : d->expressions) { if (entry.name == name) { return entry.expression; } diff --git a/src/quick/util/qquickpropertychanges_p.h b/src/quick/util/qquickpropertychanges_p.h index 74fe511d6e..82a6ebffac 100644 --- a/src/quick/util/qquickpropertychanges_p.h +++ b/src/quick/util/qquickpropertychanges_p.h @@ -101,10 +101,10 @@ public: QQuickPropertyChangesParser() : QQmlCustomParser(AcceptsAttachedProperties) {} - void verifyList(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding); + void verifyList(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QV4::CompiledData::Binding *binding); - void verifyBindings(const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props) override; - void applyBindings(QObject *obj, const QQmlRefPointer<QV4::CompiledData::CompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override; + void verifyBindings(const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &props) override; + void applyBindings(QObject *obj, const QQmlRefPointer<QV4::ExecutableCompilationUnit> &compilationUnit, const QList<const QV4::CompiledData::Binding *> &bindings) override; }; diff --git a/src/quick/util/qquickshortcut.cpp b/src/quick/util/qquickshortcut.cpp index 730a14369e..5d227b4613 100644 --- a/src/quick/util/qquickshortcut.cpp +++ b/src/quick/util/qquickshortcut.cpp @@ -216,7 +216,7 @@ void QQuickShortcut::setSequences(const QVariantList &values) bool changed = !remainder.isEmpty(); for (int i = 0; i < values.count(); ++i) { - QVariant value = values.at(i); + const QVariant &value = values.at(i); Shortcut& shortcut = m_shortcuts[i]; if (value == shortcut.userValue) continue; diff --git a/src/quick/util/qquickshortcut_p.h b/src/quick/util/qquickshortcut_p.h index c5d5501cb7..712cca7696 100644 --- a/src/quick/util/qquickshortcut_p.h +++ b/src/quick/util/qquickshortcut_p.h @@ -67,8 +67,8 @@ class QQuickShortcut : public QObject, public QQmlParserStatus Q_INTERFACES(QQmlParserStatus) Q_PROPERTY(QVariant sequence READ sequence WRITE setSequence NOTIFY sequenceChanged FINAL) Q_PROPERTY(QVariantList sequences READ sequences WRITE setSequences NOTIFY sequencesChanged FINAL REVISION 9) - Q_PROPERTY(QString nativeText READ nativeText NOTIFY sequenceChanged FINAL REVISION 1) - Q_PROPERTY(QString portableText READ portableText NOTIFY sequenceChanged FINAL REVISION 1) + Q_PROPERTY(QString nativeText READ nativeText NOTIFY sequenceChanged FINAL REVISION 6) + Q_PROPERTY(QString portableText READ portableText NOTIFY sequenceChanged FINAL REVISION 6) Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged FINAL) Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat NOTIFY autoRepeatChanged FINAL) Q_PROPERTY(Qt::ShortcutContext context READ context WRITE setContext NOTIFY contextChanged FINAL) diff --git a/src/quick/util/qquickstate.cpp b/src/quick/util/qquickstate.cpp index 3ca6440784..c106528f45 100644 --- a/src/quick/util/qquickstate.cpp +++ b/src/quick/util/qquickstate.cpp @@ -192,7 +192,7 @@ bool QQuickState::isNamed() const bool QQuickState::isWhenKnown() const { Q_D(const QQuickState); - return d->when != nullptr; + return d->whenKnown; } /*! @@ -219,15 +219,16 @@ bool QQuickState::isWhenKnown() const } \endqml */ -QQmlBinding *QQuickState::when() const +bool QQuickState::when() const { Q_D(const QQuickState); - return d->when.data(); + return d->when; } -void QQuickState::setWhen(QQmlBinding *when) +void QQuickState::setWhen(bool when) { Q_D(QQuickState); + d->whenKnown = true; d->when = when; if (d->group) d->group->updateAutoState(); @@ -371,10 +372,7 @@ bool QQuickState::containsPropertyInRevertList(QObject *target, const QString &n Q_D(const QQuickState); if (isStateActive()) { - QListIterator<QQuickSimpleAction> revertListIterator(d->revertList); - - while (revertListIterator.hasNext()) { - const QQuickSimpleAction &simpleAction = revertListIterator.next(); + for (const QQuickSimpleAction &simpleAction : d->revertList) { if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) return true; } @@ -388,10 +386,7 @@ bool QQuickState::changeValueInRevertList(QObject *target, const QString &name, Q_D(QQuickState); if (isStateActive()) { - QMutableListIterator<QQuickSimpleAction> revertListIterator(d->revertList); - - while (revertListIterator.hasNext()) { - QQuickSimpleAction &simpleAction = revertListIterator.next(); + for (QQuickSimpleAction &simpleAction : d->revertList) { if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) { simpleAction.setValue(revertValue); return true; @@ -407,10 +402,7 @@ bool QQuickState::changeBindingInRevertList(QObject *target, const QString &name Q_D(QQuickState); if (isStateActive()) { - QMutableListIterator<QQuickSimpleAction> revertListIterator(d->revertList); - - while (revertListIterator.hasNext()) { - QQuickSimpleAction &simpleAction = revertListIterator.next(); + for (QQuickSimpleAction &simpleAction : d->revertList) { if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) { simpleAction.setBinding(binding); return true; @@ -426,10 +418,8 @@ bool QQuickState::removeEntryFromRevertList(QObject *target, const QString &name Q_D(QQuickState); if (isStateActive()) { - QMutableListIterator<QQuickSimpleAction> revertListIterator(d->revertList); - - while (revertListIterator.hasNext()) { - QQuickSimpleAction &simpleAction = revertListIterator.next(); + for (auto it = d->revertList.begin(), end = d->revertList.end(); it != end; ++it) { + QQuickSimpleAction &simpleAction = *it; if (simpleAction.property().object() == target && simpleAction.property().name() == name) { QQmlPropertyPrivate::removeBinding(simpleAction.property()); @@ -437,7 +427,7 @@ bool QQuickState::removeEntryFromRevertList(QObject *target, const QString &name if (simpleAction.binding()) QQmlPropertyPrivate::setBinding(simpleAction.binding()); - revertListIterator.remove(); + d->revertList.erase(it); return true; } } @@ -460,10 +450,7 @@ void QQuickState::removeAllEntriesFromRevertList(QObject *target) Q_D(QQuickState); if (isStateActive()) { - QMutableListIterator<QQuickSimpleAction> revertListIterator(d->revertList); - - while (revertListIterator.hasNext()) { - QQuickSimpleAction &simpleAction = revertListIterator.next(); + const auto actionMatchesTarget = [target](QQuickSimpleAction &simpleAction) { if (simpleAction.property().object() == target) { QQmlPropertyPrivate::removeBinding(simpleAction.property()); @@ -471,9 +458,14 @@ void QQuickState::removeAllEntriesFromRevertList(QObject *target) if (simpleAction.binding()) QQmlPropertyPrivate::setBinding(simpleAction.binding()); - revertListIterator.remove(); + return true; } - } + return false; + }; + + d->revertList.erase(std::remove_if(d->revertList.begin(), d->revertList.end(), + actionMatchesTarget), + d->revertList.end()); } } @@ -484,9 +476,7 @@ void QQuickState::addEntriesToRevertList(const QList<QQuickStateAction> &actionL QList<QQuickSimpleAction> simpleActionList; simpleActionList.reserve(actionList.count()); - QListIterator<QQuickStateAction> actionListIterator(actionList); - while(actionListIterator.hasNext()) { - const QQuickStateAction &action = actionListIterator.next(); + for (const QQuickStateAction &action : actionList) { QQuickSimpleAction simpleAction(action); action.property.write(action.toValue); if (action.toBinding) @@ -504,10 +494,7 @@ QVariant QQuickState::valueInRevertList(QObject *target, const QString &name) co Q_D(const QQuickState); if (isStateActive()) { - QListIterator<QQuickSimpleAction> revertListIterator(d->revertList); - - while (revertListIterator.hasNext()) { - const QQuickSimpleAction &simpleAction = revertListIterator.next(); + for (const QQuickSimpleAction &simpleAction : d->revertList) { if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) return simpleAction.value(); } @@ -521,10 +508,7 @@ QQmlAbstractBinding *QQuickState::bindingInRevertList(QObject *target, const QSt Q_D(const QQuickState); if (isStateActive()) { - QListIterator<QQuickSimpleAction> revertListIterator(d->revertList); - - while (revertListIterator.hasNext()) { - const QQuickSimpleAction &simpleAction = revertListIterator.next(); + for (const QQuickSimpleAction &simpleAction : d->revertList) { if (simpleAction.specifiedObject() == target && simpleAction.specifiedProperty() == name) return simpleAction.binding(); } diff --git a/src/quick/util/qquickstate_p.h b/src/quick/util/qquickstate_p.h index 79874ee78e..576ba9834c 100644 --- a/src/quick/util/qquickstate_p.h +++ b/src/quick/util/qquickstate_p.h @@ -152,7 +152,7 @@ class Q_QUICK_PRIVATE_EXPORT QQuickState : public QObject Q_OBJECT Q_PROPERTY(QString name READ name WRITE setName) - Q_PROPERTY(QQmlBinding *when READ when WRITE setWhen) + Q_PROPERTY(bool when READ when WRITE setWhen) Q_PROPERTY(QString extend READ extends WRITE setExtends) Q_PROPERTY(QQmlListProperty<QQuickStateOperation> changes READ changes) Q_CLASSINFO("DefaultProperty", "changes") @@ -166,11 +166,9 @@ public: void setName(const QString &); bool isNamed() const; - /*'when' is a QQmlBinding to limit state changes oscillation - due to the unpredictable order of evaluation of bound expressions*/ bool isWhenKnown() const; - QQmlBinding *when() const; - void setWhen(QQmlBinding *); + bool when() const; + void setWhen(bool); QString extends() const; void setExtends(const QString &); diff --git a/src/quick/util/qquickstate_p_p.h b/src/quick/util/qquickstate_p_p.h index 61472b4d06..2fa5321165 100644 --- a/src/quick/util/qquickstate_p_p.h +++ b/src/quick/util/qquickstate_p_p.h @@ -203,12 +203,13 @@ class QQuickStatePrivate : public QObjectPrivate public: QQuickStatePrivate() - : named(false), inState(false), group(nullptr) {} + : when(false), whenKnown(false), named(false), inState(false), group(nullptr) {} typedef QList<QQuickSimpleAction> SimpleActionList; QString name; - QQmlBinding::Ptr when; + bool when; + bool whenKnown; bool named; struct OperationGuard : public QQmlGuard<QQuickStateOperation> @@ -231,9 +232,8 @@ public: } static void operations_clear(QQmlListProperty<QQuickStateOperation> *prop) { QList<OperationGuard> *list = static_cast<QList<OperationGuard> *>(prop->data); - QMutableListIterator<OperationGuard> listIterator(*list); - while(listIterator.hasNext()) - listIterator.next()->setState(nullptr); + for (auto &e : *list) + e->setState(nullptr); list->clear(); } static int operations_count(QQmlListProperty<QQuickStateOperation> *prop) { diff --git a/src/quick/util/qquickstategroup.cpp b/src/quick/util/qquickstategroup.cpp index b53949d21c..46e7d62fc1 100644 --- a/src/quick/util/qquickstategroup.cpp +++ b/src/quick/util/qquickstategroup.cpp @@ -311,7 +311,7 @@ void QQuickStateGroup::componentComplete() if (!state->isNamed()) state->setName(QLatin1String("anonymousState") + QString::number(++d->unnamedCount)); - const QString stateName = state->name(); + QString stateName = state->name(); if (names.contains(stateName)) { qmlWarning(state->parent()) << "Found duplicate state name: " << stateName; } else { @@ -348,10 +348,9 @@ bool QQuickStateGroupPrivate::updateAutoState() QQuickState *state = states.at(ii); if (state->isWhenKnown()) { if (state->isNamed()) { - if (state->when() && state->when()->evaluate().toBool()) { + if (state->when()) { if (stateChangeDebug()) - qWarning() << "Setting auto state due to:" - << state->when()->expression(); + qWarning() << "Setting auto state due to expression"; if (currentState != state->name()) { q->setState(state->name()); return true; diff --git a/src/quick/util/qquickutilmodule.cpp b/src/quick/util/qquickutilmodule.cpp index 5147ebc6f6..93b6599506 100644 --- a/src/quick/util/qquickutilmodule.cpp +++ b/src/quick/util/qquickutilmodule.cpp @@ -99,10 +99,13 @@ void QQuickUtilModule::defineModule() qmlRegisterType<QQuickVector3dAnimation>("QtQuick",2,0,"Vector3dAnimation"); #if QT_CONFIG(validator) - qmlRegisterType<QValidator>(); + qmlRegisterAnonymousType<QValidator>("QtQuick", 2); qmlRegisterType<QQuickIntValidator>("QtQuick",2,0,"IntValidator"); qmlRegisterType<QQuickDoubleValidator>("QtQuick",2,0,"DoubleValidator"); qmlRegisterType<QRegExpValidator>("QtQuick",2,0,"RegExpValidator"); +#if QT_CONFIG(regularexpression) + qmlRegisterType<QRegularExpressionValidator>("QtQuick", 2, 14, "RegularExpressionValidator"); +#endif #endif qmlRegisterUncreatableType<QQuickAnimator>("QtQuick", 2, 2, "Animator", QQuickAbstractAnimation::tr("Animator is an abstract class")); @@ -114,7 +117,7 @@ void QQuickUtilModule::defineModule() #if QT_CONFIG(quick_shadereffect) && QT_CONFIG(opengl) qmlRegisterType<QQuickUniformAnimator>("QtQuick", 2, 2, "UniformAnimator"); #endif - qmlRegisterType<QQuickStateOperation>(); + qmlRegisterAnonymousType<QQuickStateOperation>("QtQuick", 2); qmlRegisterCustomType<QQuickPropertyChanges>("QtQuick",2,0,"PropertyChanges", new QQuickPropertyChangesParser); @@ -128,7 +131,7 @@ void QQuickUtilModule::defineModule() #if QT_CONFIG(shortcut) qmlRegisterType<QQuickShortcut>("QtQuick", 2, 5, "Shortcut"); - qmlRegisterType<QQuickShortcut,1>("QtQuick", 2, 6, "Shortcut"); + qmlRegisterType<QQuickShortcut,6>("QtQuick", 2, 6, "Shortcut"); qmlRegisterType<QQuickShortcut,9>("QtQuick", 2, 9, "Shortcut"); #endif diff --git a/src/quick/util/qquickvalidator.cpp b/src/quick/util/qquickvalidator.cpp index b2b773cd94..4709b3dda3 100644 --- a/src/quick/util/qquickvalidator.cpp +++ b/src/quick/util/qquickvalidator.cpp @@ -206,9 +206,13 @@ void QQuickDoubleValidator::resetLocaleName() \inqmlmodule QtQuick \ingroup qtquick-text-utility \brief Provides a string validator. + \deprecated The RegExpValidator type provides a validator, which counts as valid any string which matches a specified regular expression. + + RegExpValidator is deprecated since it is based on the deprecated \l {QRegExp}. Use + \l RegularExpressionValidator instead. */ /*! \qmlproperty regExp QtQuick::RegExpValidator::regExp @@ -239,6 +243,48 @@ void QQuickDoubleValidator::resetLocaleName() \endcode \endlist */ +/*! + \qmltype RegularExpressionValidator + \instantiates QRegularExpressionValidator + \inqmlmodule QtQuick + \ingroup qtquick-text-utility + \brief Provides a string validator. + \since 5.14 + + The RegularExpressionValidator type provides a validator, that counts as valid any string which + matches a specified regular expression. +*/ +/*! + \qmlproperty regularExpression QtQuick::RegularExpressionValidator::regularExpression + + This property holds the regular expression used for validation. + + Note that this property should be a regular expression in JS syntax, e.g /a/ for the regular + expression matching "a". + + By default, this property contains a regular expression with the pattern \c{.*} that matches any + string. + + Below you can find an example of a \l TextInput object with a RegularExpressionValidator + specified: + + \snippet qml/regularexpression.qml 0 + + Some more examples of regular expressions: + + \list + \li A list of numbers with one to three positions separated by a comma: + \badcode + /\d{1,3}(?:,\d{1,3})+$/ + \endcode + + \li An amount consisting of up to 3 numbers before the decimal point, and + 1 to 2 after the decimal point: + \badcode + /(\d{1,3})([.,]\d{1,2})?$/ + \endcode + \endlist +*/ #endif // validator diff --git a/src/quick/util/qquickvalidator_p.h b/src/quick/util/qquickvalidator_p.h index 812e552d8e..9212efa044 100644 --- a/src/quick/util/qquickvalidator_p.h +++ b/src/quick/util/qquickvalidator_p.h @@ -95,6 +95,9 @@ QML_DECLARE_TYPE(QValidator) QML_DECLARE_TYPE(QQuickIntValidator) QML_DECLARE_TYPE(QQuickDoubleValidator) QML_DECLARE_TYPE(QRegExpValidator) +#if QT_CONFIG(regularexpression) +QML_DECLARE_TYPE(QRegularExpressionValidator) +#endif #endif #endif // QQUICKVALIDATOR_P_H diff --git a/src/quick/util/qquickvaluetypes.cpp b/src/quick/util/qquickvaluetypes.cpp index e4a03f3b52..0af29aed1c 100644 --- a/src/quick/util/qquickvaluetypes.cpp +++ b/src/quick/util/qquickvaluetypes.cpp @@ -109,6 +109,11 @@ qreal QQuickColorValueType::hslLightness() const return v.lightnessF(); } +bool QQuickColorValueType::isValid() const +{ + return v.isValid(); +} + void QQuickColorValueType::setR(qreal r) { v.setRedF(r); diff --git a/src/quick/util/qquickvaluetypes_p.h b/src/quick/util/qquickvaluetypes_p.h index 5a9af970e8..4305006f91 100644 --- a/src/quick/util/qquickvaluetypes_p.h +++ b/src/quick/util/qquickvaluetypes_p.h @@ -84,6 +84,7 @@ class QQuickColorValueType Q_PROPERTY(qreal hslHue READ hslHue WRITE setHslHue FINAL) Q_PROPERTY(qreal hslSaturation READ hslSaturation WRITE setHslSaturation FINAL) Q_PROPERTY(qreal hslLightness READ hslLightness WRITE setHslLightness FINAL) + Q_PROPERTY(bool valid READ isValid) Q_GADGET public: Q_INVOKABLE QString toString() const; @@ -98,6 +99,7 @@ public: qreal hslHue() const; qreal hslSaturation() const; qreal hslLightness() const; + bool isValid() const; void setR(qreal); void setG(qreal); void setB(qreal); diff --git a/src/quick/util/util.pri b/src/quick/util/util.pri index c51f082d03..63d995e34c 100644 --- a/src/quick/util/util.pri +++ b/src/quick/util/util.pri @@ -15,6 +15,7 @@ SOURCES += \ $$PWD/qquicktimeline.cpp \ $$PWD/qquickpixmapcache.cpp \ $$PWD/qquickbehavior.cpp \ + $$PWD/qquickboundaryrule.cpp \ $$PWD/qquickfontloader.cpp \ $$PWD/qquickstyledtext.cpp \ $$PWD/qquickimageprovider.cpp \ @@ -50,6 +51,7 @@ HEADERS += \ $$PWD/qquicktimeline_p_p.h \ $$PWD/qquickpixmapcache_p.h \ $$PWD/qquickbehavior_p.h \ + $$PWD/qquickboundaryrule_p.h \ $$PWD/qquickfontloader_p.h \ $$PWD/qquickstyledtext_p.h \ $$PWD/qquickimageprovider.h \ |