diff options
52 files changed, 1225 insertions, 1263 deletions
diff --git a/.qmake.conf b/.qmake.conf index 0104dac8..8114dfd7 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -4,4 +4,4 @@ DEFINES += QT_NO_FOREACH QQC2_SOURCE_TREE = $$PWD -MODULE_VERSION = 5.8.0 +MODULE_VERSION = 5.9.0 diff --git a/src/imports/controls/BusyIndicator.qml b/src/imports/controls/BusyIndicator.qml index 936764fa..16fb6091 100644 --- a/src/imports/controls/BusyIndicator.qml +++ b/src/imports/controls/BusyIndicator.qml @@ -48,18 +48,13 @@ T.BusyIndicator { padding: 6 //! [contentItem] - contentItem: BusyRing { - id: ring + contentItem: BusyIndicatorImpl { implicitWidth: 48 implicitHeight: 48 - opacity: control.running ? 1 : 0 - - Behavior on opacity { OpacityAnimator { duration: 250 } } - BusyRingAnimator { - target: ring - running: control.visible && control.running - } + opacity: control.running ? 1 : 0 + visible: control.running || animator.running + Behavior on opacity { OpacityAnimator { id: animator; duration: 250 } } } //! [contentItem] } diff --git a/src/imports/controls/Dial.qml b/src/imports/controls/Dial.qml index f19fcc2b..e4579ca9 100644 --- a/src/imports/controls/Dial.qml +++ b/src/imports/controls/Dial.qml @@ -35,9 +35,9 @@ ****************************************************************************/ import QtQuick 2.8 -import QtQuick.Controls 2.1 +import QtQuick.Controls 2.2 import QtQuick.Controls.impl 2.1 -import QtQuick.Templates 2.1 as T +import QtQuick.Templates 2.2 as T T.Dial { id: control diff --git a/src/imports/controls/ProgressBar.qml b/src/imports/controls/ProgressBar.qml index a0d0912a..130adcec 100644 --- a/src/imports/controls/ProgressBar.qml +++ b/src/imports/controls/ProgressBar.qml @@ -48,18 +48,12 @@ T.ProgressBar { contentItem.implicitHeight + topPadding + bottomPadding) //! [contentItem] - contentItem: ProgressStrip { - id: strip + contentItem: ProgressBarImpl { implicitHeight: 6 implicitWidth: 116 scale: control.mirrored ? -1 : 1 progress: control.position - indeterminate: control.indeterminate - - ProgressStripAnimator { - target: strip - running: control.visible && control.indeterminate - } + indeterminate: control.visible && control.indeterminate } //! [contentItem] diff --git a/src/imports/controls/RangeSlider.qml b/src/imports/controls/RangeSlider.qml index 6b892fd1..005fa99c 100644 --- a/src/imports/controls/RangeSlider.qml +++ b/src/imports/controls/RangeSlider.qml @@ -35,9 +35,9 @@ ****************************************************************************/ import QtQuick 2.8 -import QtQuick.Controls 2.1 +import QtQuick.Controls 2.2 import QtQuick.Controls.impl 2.1 -import QtQuick.Templates 2.1 as T +import QtQuick.Templates 2.2 as T T.RangeSlider { id: control diff --git a/src/imports/controls/Slider.qml b/src/imports/controls/Slider.qml index f7e95db9..d2aba229 100644 --- a/src/imports/controls/Slider.qml +++ b/src/imports/controls/Slider.qml @@ -35,9 +35,9 @@ ****************************************************************************/ import QtQuick 2.8 -import QtQuick.Controls 2.1 +import QtQuick.Controls 2.2 import QtQuick.Controls.impl 2.1 -import QtQuick.Templates 2.1 as T +import QtQuick.Templates 2.2 as T T.Slider { id: control diff --git a/src/imports/controls/Tumbler.qml b/src/imports/controls/Tumbler.qml index 6c89b86d..0be6c074 100644 --- a/src/imports/controls/Tumbler.qml +++ b/src/imports/controls/Tumbler.qml @@ -35,9 +35,9 @@ ****************************************************************************/ import QtQuick 2.8 -import QtQuick.Controls 2.1 +import QtQuick.Controls 2.2 import QtQuick.Controls.impl 2.1 -import QtQuick.Templates 2.1 as T +import QtQuick.Templates 2.2 as T T.Tumbler { id: control diff --git a/src/imports/controls/controls.pri b/src/imports/controls/controls.pri index 79e03db5..8a262694 100644 --- a/src/imports/controls/controls.pri +++ b/src/imports/controls/controls.pri @@ -1,13 +1,13 @@ HEADERS += \ - $$PWD/qquickbusyindicatorring_p.h \ - $$PWD/qquickprogressstrip_p.h \ $$PWD/qquickdialring_p.h \ - $$PWD/qquickdefaultstyle_p.h + $$PWD/qquickdefaultbusyindicator_p.h \ + $$PWD/qquickdefaultprogressbar_p.h \ + $$PWD/qquickdefaultstyle_p.h \ SOURCES += \ - $$PWD/qquickbusyindicatorring.cpp \ - $$PWD/qquickprogressstrip.cpp \ $$PWD/qquickdialring.cpp \ + $$PWD/qquickdefaultbusyindicator.cpp \ + $$PWD/qquickdefaultprogressbar.cpp \ $$PWD/qquickdefaultstyle.cpp QML_CONTROLS = \ diff --git a/src/imports/controls/material/BusyIndicator.qml b/src/imports/controls/material/BusyIndicator.qml index 3077ceb7..5a17c002 100644 --- a/src/imports/controls/material/BusyIndicator.qml +++ b/src/imports/controls/material/BusyIndicator.qml @@ -47,24 +47,13 @@ T.BusyIndicator { padding: 6 - contentItem: ProgressRing { - id: ring - x: control.leftPadding + (control.availableWidth - width) / 2 - y: control.topPadding + (control.availableHeight - height) / 2 + contentItem: BusyIndicatorImpl { implicitWidth: 48 implicitHeight: 48 - width: size - height: size - opacity: control.running ? 1 : 0 color: control.Material.accentColor - readonly property real size: Math.min(control.availableWidth, control.availableHeight) - - Behavior on opacity { OpacityAnimator { duration: 250 } } - - RingAnimator { - target: ring - running: control.visible && control.running - } + opacity: control.running ? 1 : 0 + visible: control.running || animator.running + Behavior on opacity { OpacityAnimator { id: animator; duration: 250 } } } } diff --git a/src/imports/controls/material/Dial.qml b/src/imports/controls/material/Dial.qml index ce76c2a7..30bc9308 100644 --- a/src/imports/controls/material/Dial.qml +++ b/src/imports/controls/material/Dial.qml @@ -35,7 +35,7 @@ ****************************************************************************/ import QtQuick 2.8 -import QtQuick.Templates 2.1 as T +import QtQuick.Templates 2.2 as T import QtQuick.Controls.Material 2.1 import QtQuick.Controls.Material.impl 2.1 diff --git a/src/imports/controls/material/ProgressBar.qml b/src/imports/controls/material/ProgressBar.qml index 2b78be49..54152895 100644 --- a/src/imports/controls/material/ProgressBar.qml +++ b/src/imports/controls/material/ProgressBar.qml @@ -47,19 +47,13 @@ T.ProgressBar { implicitHeight: Math.max(background ? background.implicitHeight : 0, contentItem.implicitHeight + topPadding + bottomPadding) - contentItem: ProgressStrip { - id: strip + contentItem: ProgressBarImpl { implicitHeight: 4 scale: control.mirrored ? -1 : 1 - indeterminate: control.indeterminate color: control.Material.accentColor progress: control.position - - StripAnimator { - target: strip - running: control.visible && control.indeterminate - } + indeterminate: control.visible && control.indeterminate } background: Rectangle { diff --git a/src/imports/controls/material/RangeSlider.qml b/src/imports/controls/material/RangeSlider.qml index 4381fd41..2442a38b 100644 --- a/src/imports/controls/material/RangeSlider.qml +++ b/src/imports/controls/material/RangeSlider.qml @@ -35,7 +35,7 @@ ****************************************************************************/ import QtQuick 2.8 -import QtQuick.Templates 2.1 as T +import QtQuick.Templates 2.2 as T import QtQuick.Controls.Material 2.1 import QtQuick.Controls.Material.impl 2.1 diff --git a/src/imports/controls/material/Slider.qml b/src/imports/controls/material/Slider.qml index 7cf858e7..fb871a02 100644 --- a/src/imports/controls/material/Slider.qml +++ b/src/imports/controls/material/Slider.qml @@ -35,7 +35,7 @@ ****************************************************************************/ import QtQuick 2.8 -import QtQuick.Templates 2.1 as T +import QtQuick.Templates 2.2 as T import QtQuick.Controls.Material 2.1 import QtQuick.Controls.Material.impl 2.1 diff --git a/src/imports/controls/material/Tumbler.qml b/src/imports/controls/material/Tumbler.qml index 88750855..06a012f6 100644 --- a/src/imports/controls/material/Tumbler.qml +++ b/src/imports/controls/material/Tumbler.qml @@ -35,9 +35,9 @@ ****************************************************************************/ import QtQuick 2.8 -import QtQuick.Controls 2.1 +import QtQuick.Controls 2.2 import QtQuick.Controls.impl 2.1 -import QtQuick.Templates 2.1 as T +import QtQuick.Templates 2.2 as T import QtQuick.Controls.Material 2.1 T.Tumbler { diff --git a/src/imports/controls/material/material.pri b/src/imports/controls/material/material.pri index 3170a695..355d62a5 100644 --- a/src/imports/controls/material/material.pri +++ b/src/imports/controls/material/material.pri @@ -1,16 +1,16 @@ HEADERS += \ + $$PWD/qquickmaterialbusyindicator_p.h \ + $$PWD/qquickmaterialprogressbar_p.h \ $$PWD/qquickmaterialripple_p.h \ $$PWD/qquickmaterialstyle_p.h \ - $$PWD/qquickmaterialtheme_p.h \ - $$PWD/qquickmaterialprogressring_p.h \ - $$PWD/qquickmaterialprogressstrip_p.h + $$PWD/qquickmaterialtheme_p.h SOURCES += \ + $$PWD/qquickmaterialbusyindicator.cpp \ + $$PWD/qquickmaterialprogressbar.cpp \ $$PWD/qquickmaterialripple.cpp \ $$PWD/qquickmaterialstyle.cpp \ - $$PWD/qquickmaterialtheme.cpp \ - $$PWD/qquickmaterialprogressring.cpp \ - $$PWD/qquickmaterialprogressstrip.cpp + $$PWD/qquickmaterialtheme.cpp QML_FILES += \ $$PWD/ApplicationWindow.qml \ diff --git a/src/imports/controls/material/qquickmaterialprogressring.cpp b/src/imports/controls/material/qquickmaterialbusyindicator.cpp index a3564c17..d55b131b 100644 --- a/src/imports/controls/material/qquickmaterialprogressring.cpp +++ b/src/imports/controls/material/qquickmaterialbusyindicator.cpp @@ -34,14 +34,12 @@ ** ****************************************************************************/ -#include "qquickmaterialprogressring_p.h" +#include "qquickmaterialbusyindicator_p.h" -#include <cmath> - -#include <QtCore/qset.h> +#include <QtCore/qeasingcurve.h> +#include <QtCore/qelapsedtimer.h> #include <QtGui/qpainter.h> #include <QtQuick/private/qquickitem_p.h> -#include <QtQuick/qsgrectanglenode.h> #include <QtQuick/qsgimagenode.h> #include <QtQuick/qquickwindow.h> @@ -61,200 +59,186 @@ QT_BEGIN_NAMESPACE different path commands available. */ -class QQuickMaterialRingAnimatorJob : public QQuickAnimatorJob +static const int SpanAnimationDuration = 700; +static const int RotationAnimationDuration = SpanAnimationDuration * 6; +static const int TargetRotation = 720; +static const int OneDegree = 16; +static const qreal MinSweepSpan = 10 * OneDegree; +static const qreal MaxSweepSpan = 300 * OneDegree; + +class QQuickMaterialBusyIndicatorNode : public QObject, public QSGNode { public: - QQuickMaterialRingAnimatorJob(); - ~QQuickMaterialRingAnimatorJob(); + QQuickMaterialBusyIndicatorNode(QQuickMaterialBusyIndicator *item); + + int elapsed() const; - void initialize(QQuickAnimatorController *controller) override; - void updateCurrentTime(int time) override; - void writeBack() override; - void nodeWasDestroyed() override; - void afterNodeSync() override; + void animate(); + void sync(QQuickMaterialBusyIndicator *item); private: + int m_offset; int m_lastStartAngle; int m_lastEndAngle; + qreal m_width; + qreal m_height; qreal m_devicePixelRatio; QSGNode *m_containerNode; QQuickWindow *m_window; + QElapsedTimer m_timer; QColor m_color; }; -QQuickMaterialProgressRing::QQuickMaterialProgressRing(QQuickItem *parent) : - QQuickItem(parent) -{ - setFlag(QQuickItem::ItemHasContents); -} - -QQuickMaterialProgressRing::~QQuickMaterialProgressRing() -{ -} - -QSGNode *QQuickMaterialProgressRing::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *) +QQuickMaterialBusyIndicatorNode::QQuickMaterialBusyIndicatorNode(QQuickMaterialBusyIndicator *item) : + m_offset(item->elapsed()), + m_lastStartAngle(0), + m_lastEndAngle(0), + m_width(0), + m_height(0), + m_devicePixelRatio(1), + m_window(item->window()) { - if (!oldNode) { - oldNode = window()->createRectangleNode(); - static_cast<QSGRectangleNode *>(oldNode)->setColor(Qt::transparent); - } - static_cast<QSGRectangleNode *>(oldNode)->setRect(boundingRect()); + connect(m_window, &QQuickWindow::frameSwapped, m_window, &QQuickWindow::update); + connect(m_window, &QQuickWindow::beforeRendering, this, &QQuickMaterialBusyIndicatorNode::animate); - QSGImageNode *textureNode = static_cast<QSGImageNode *>(oldNode->firstChild()); - if (!textureNode) { - textureNode = window()->createImageNode(); - textureNode->setOwnsTexture(true); - oldNode->appendChildNode(textureNode); - } + QSGImageNode *textureNode = m_window->createImageNode(); + textureNode->setOwnsTexture(true); + appendChildNode(textureNode); // A texture seems to be required here, but we don't have one yet, as we haven't drawn anything, // so just use a blank image. - QImage blankImage(width(), height(), QImage::Format_ARGB32_Premultiplied); + QImage blankImage(item->width(), item->height(), QImage::Format_ARGB32_Premultiplied); blankImage.fill(Qt::transparent); - textureNode->setRect(boundingRect()); - textureNode->setTexture(window()->createTextureFromImage(blankImage)); - - return oldNode; -} - -QColor QQuickMaterialProgressRing::color() const -{ - return m_color; -} - -void QQuickMaterialProgressRing::setColor(QColor color) -{ - if (m_color == color) - return; - - m_color = color; - update(); - emit colorChanged(); -} - -static const int spanAnimationDuration = 700; -static const int rotationAnimationDuration = spanAnimationDuration * 6; -static const int targetRotation = 720; -static const int oneDegree = 16; -static const qreal minSweepSpan = 10 * oneDegree; -static const qreal maxSweepSpan = 300 * oneDegree; + textureNode->setTexture(m_window->createTextureFromImage(blankImage)); -QQuickMaterialRingAnimator::QQuickMaterialRingAnimator(QObject *parent) : - QQuickAnimator(parent) -{ - setDuration(rotationAnimationDuration); - setLoops(QQuickAnimator::Infinite); + m_timer.restart(); } -QString QQuickMaterialRingAnimator::propertyName() const +int QQuickMaterialBusyIndicatorNode::elapsed() const { - return QString(); + return m_timer.elapsed() + m_offset; } -QQuickAnimatorJob *QQuickMaterialRingAnimator::createJob() const +void QQuickMaterialBusyIndicatorNode::animate() { - return new QQuickMaterialRingAnimatorJob; -} - -QQuickMaterialRingAnimatorJob::QQuickMaterialRingAnimatorJob() : - m_lastStartAngle(0), - m_lastEndAngle(0), - m_devicePixelRatio(1.0), - m_containerNode(nullptr), - m_window(nullptr) -{ -} - -QQuickMaterialRingAnimatorJob::~QQuickMaterialRingAnimatorJob() -{ -} - -void QQuickMaterialRingAnimatorJob::initialize(QQuickAnimatorController *controller) -{ - QQuickAnimatorJob::initialize(controller); - m_containerNode = QQuickItemPrivate::get(m_target)->childContainerNode(); - m_window = m_target->window(); - m_devicePixelRatio = m_window->effectiveDevicePixelRatio(); -} - -void QQuickMaterialRingAnimatorJob::updateCurrentTime(int time) -{ - if (!m_containerNode) - return; - - QSGRectangleNode *rectNode = static_cast<QSGRectangleNode *>(m_containerNode->firstChild()); - if (!rectNode) - return; + qint64 time = m_timer.elapsed() + m_offset; + if (time >= RotationAnimationDuration) { + m_timer.restart(); + m_offset = 0; + } - Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType); + const qreal w = m_width; + const qreal h = m_height; + const qreal size = qMin(w, h); + const qreal dx = (w - size) / 2; + const qreal dy = (h - size) / 2; - const qreal width = rectNode->rect().width() * m_devicePixelRatio; - const qreal height = rectNode->rect().height() * m_devicePixelRatio; - QImage image(width, height, QImage::Format_ARGB32_Premultiplied); + QImage image(size * m_devicePixelRatio, size * m_devicePixelRatio, QImage::Format_ARGB32_Premultiplied); image.fill(Qt::transparent); QPainter painter(&image); painter.setRenderHint(QPainter::Antialiasing); QPen pen; - QSGImageNode *textureNode = static_cast<QSGImageNode *>(rectNode->firstChild()); + QSGImageNode *textureNode = static_cast<QSGImageNode *>(firstChild()); pen.setColor(m_color); pen.setWidth(4 * m_devicePixelRatio); painter.setPen(pen); - const qreal percentageComplete = time / qreal(rotationAnimationDuration); - const qreal spanPercentageComplete = (time % spanAnimationDuration) / qreal(spanAnimationDuration); - const int iteration = time / spanAnimationDuration; + const qreal percentageComplete = time / qreal(RotationAnimationDuration); + const qreal spanPercentageComplete = (time % SpanAnimationDuration) / qreal(SpanAnimationDuration); + const int iteration = time / SpanAnimationDuration; int startAngle = 0; int endAngle = 0; if (iteration % 2 == 0) { - if (m_lastStartAngle > 360 * oneDegree) { - m_lastStartAngle -= 360 * oneDegree; - } + if (m_lastStartAngle > 360 * OneDegree) + m_lastStartAngle -= 360 * OneDegree; // The start angle is only affected by the rotation animation for the "grow" phase. startAngle = m_lastStartAngle; QEasingCurve angleCurve(QEasingCurve::OutQuad); const qreal percentage = angleCurve.valueForProgress(spanPercentageComplete); - endAngle = m_lastStartAngle + minSweepSpan + percentage * (maxSweepSpan - minSweepSpan); + endAngle = m_lastStartAngle + MinSweepSpan + percentage * (MaxSweepSpan - MinSweepSpan); m_lastEndAngle = endAngle; } else { // Both the start angle *and* the span are affected by the "shrink" phase. QEasingCurve angleCurve(QEasingCurve::InQuad); const qreal percentage = angleCurve.valueForProgress(spanPercentageComplete); - startAngle = m_lastEndAngle - maxSweepSpan + percentage * (maxSweepSpan - minSweepSpan); + startAngle = m_lastEndAngle - MaxSweepSpan + percentage * (MaxSweepSpan - MinSweepSpan); endAngle = m_lastEndAngle; m_lastStartAngle = startAngle; } const int halfPen = pen.width() / 2; - const QRectF arcBounds = QRectF(halfPen, halfPen, width - pen.width(), height - pen.width()); + const QRectF arcBounds = QRectF(halfPen, halfPen, + m_devicePixelRatio * size - pen.width(), + m_devicePixelRatio * size - pen.width()); // The current angle of the rotation animation. - const qreal rotation = oneDegree * percentageComplete * -targetRotation; + const qreal rotation = OneDegree * percentageComplete * -TargetRotation; startAngle -= rotation; endAngle -= rotation; const int angleSpan = endAngle - startAngle; painter.drawArc(arcBounds, -startAngle, -angleSpan); painter.end(); + textureNode->setRect(QRectF(dx, dy, size, size)); textureNode->setTexture(m_window->createTextureFromImage(image)); } -void QQuickMaterialRingAnimatorJob::writeBack() +void QQuickMaterialBusyIndicatorNode::sync(QQuickMaterialBusyIndicator *item) { + m_color = item->color(); + m_width = item->width(); + m_height = item->height(); + m_devicePixelRatio = m_window->effectiveDevicePixelRatio(); } -void QQuickMaterialRingAnimatorJob::nodeWasDestroyed() +QQuickMaterialBusyIndicator::QQuickMaterialBusyIndicator(QQuickItem *parent) : + QQuickItem(parent) { - m_containerNode = nullptr; - m_window = nullptr; + setFlag(ItemHasContents); } -void QQuickMaterialRingAnimatorJob::afterNodeSync() +QColor QQuickMaterialBusyIndicator::color() const { - m_containerNode = QQuickItemPrivate::get(m_target)->childContainerNode(); - m_color = static_cast<QQuickMaterialProgressRing *>(m_target.data())->color(); + return m_color; +} + +void QQuickMaterialBusyIndicator::setColor(QColor color) +{ + if (m_color == color) + return; + + m_color = color; + update(); +} + +int QQuickMaterialBusyIndicator::elapsed() const +{ + return m_elapsed; +} + +void QQuickMaterialBusyIndicator::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) +{ + QQuickItem::itemChange(change, data); + if (change == ItemVisibleHasChanged) + update(); +} + +QSGNode *QQuickMaterialBusyIndicator::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) +{ + QQuickMaterialBusyIndicatorNode *node = static_cast<QQuickMaterialBusyIndicatorNode *>(oldNode); + if (isVisible() && width() > 0 && height() > 0) { + if (!node) + node = new QQuickMaterialBusyIndicatorNode(this); + node->sync(this); + } else { + m_elapsed = node ? node->elapsed() : 0; + delete node; + node = nullptr; + } + return node; } QT_END_NAMESPACE diff --git a/src/imports/controls/material/qquickmaterialprogressring_p.h b/src/imports/controls/material/qquickmaterialbusyindicator_p.h index 8d6cd578..4772d164 100644 --- a/src/imports/controls/material/qquickmaterialprogressring_p.h +++ b/src/imports/controls/material/qquickmaterialbusyindicator_p.h @@ -34,8 +34,8 @@ ** ****************************************************************************/ -#ifndef QQUICKMATERIALPROGRESSRING_P_H -#define QQUICKMATERIALPROGRESSRING_P_H +#ifndef QQUICKMATERIALBUSYINDICATOR_P_H +#define QQUICKMATERIALBUSYINDICATOR_P_H // // W A R N I N G @@ -50,44 +50,33 @@ #include <QtGui/qcolor.h> #include <QtQuick/qquickitem.h> -#include <QtQuick/private/qquickanimatorjob_p.h> QT_BEGIN_NAMESPACE -class QQuickMaterialProgressRing : public QQuickItem +class QQuickMaterialBusyIndicator : public QQuickItem { Q_OBJECT - Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged FINAL) + Q_PROPERTY(QColor color READ color WRITE setColor FINAL) public: - explicit QQuickMaterialProgressRing(QQuickItem *parent = nullptr); - ~QQuickMaterialProgressRing(); + explicit QQuickMaterialBusyIndicator(QQuickItem *parent = nullptr); QColor color() const; void setColor(QColor color); -Q_SIGNALS: - void colorChanged(); + int elapsed() const; protected: + void itemChange(ItemChange change, const ItemChangeData &data) override; QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override; private: + int m_elapsed; QColor m_color; }; -class QQuickMaterialRingAnimator : public QQuickAnimator -{ -public: - QQuickMaterialRingAnimator(QObject *parent = nullptr); - -protected: - QString propertyName() const override; - QQuickAnimatorJob *createJob() const override; -}; - QT_END_NAMESPACE -QML_DECLARE_TYPE(QQuickMaterialProgressRing) +QML_DECLARE_TYPE(QQuickMaterialBusyIndicator) -#endif // QQUICKMATERIALPROGRESSRING_P_H +#endif // QQUICKMATERIALBUSYINDICATOR_P_H diff --git a/src/imports/controls/material/qquickmaterialprogressstrip.cpp b/src/imports/controls/material/qquickmaterialprogressbar.cpp index 542d312f..36b18781 100644 --- a/src/imports/controls/material/qquickmaterialprogressstrip.cpp +++ b/src/imports/controls/material/qquickmaterialprogressbar.cpp @@ -34,12 +34,12 @@ ** ****************************************************************************/ -#include "qquickmaterialprogressstrip_p.h" +#include "qquickmaterialprogressbar_p.h" #include <QtCore/qmath.h> #include <QtCore/qeasingcurve.h> +#include <QtCore/qelapsedtimer.h> #include <QtQuick/private/qquickitem_p.h> -#include <QtQuick/private/qquickanimatorjob_p.h> #include <QtQuick/private/qsgadaptationlayer_p.h> #include <QtQuick/qsgrectanglenode.h> #include <QtQuick/qsgimagenode.h> @@ -50,43 +50,36 @@ static const int PauseDuration = 520; static const int SlideDuration = 1240; static const int TotalDuration = SlideDuration + PauseDuration; -class QQuickMaterialProgressStripAnimatorJob : public QQuickAnimatorJob +class QQuickMaterialProgressBarNode : public QObject, public QSGNode { public: - QQuickMaterialProgressStripAnimatorJob(); + QQuickMaterialProgressBarNode(QQuickMaterialProgressBar *item); - void initialize(QQuickAnimatorController *controller) override; - void updateCurrentTime(int time) override; - void writeBack() override; - void nodeWasDestroyed() override; - void afterNodeSync() override; + void animate(); + void sync(QQuickMaterialProgressBar *item); +private: void moveNode(QSGTransformNode *node, const QRectF &geometry, qreal progress); -private: - QSGNode *m_node; + bool m_indeterminate; + QElapsedTimer m_timer; + QEasingCurve m_easing; }; -QQuickMaterialProgressStripAnimatorJob::QQuickMaterialProgressStripAnimatorJob() : m_node(nullptr) -{ -} - -void QQuickMaterialProgressStripAnimatorJob::initialize(QQuickAnimatorController *controller) +QQuickMaterialProgressBarNode::QQuickMaterialProgressBarNode(QQuickMaterialProgressBar *) + : m_indeterminate(false), m_easing(QEasingCurve::OutCubic) { - QQuickAnimatorJob::initialize(controller); - m_node = QQuickItemPrivate::get(m_target)->childContainerNode(); + m_timer.start(); } -void QQuickMaterialProgressStripAnimatorJob::updateCurrentTime(int time) +void QQuickMaterialProgressBarNode::animate() { - if (!m_node) - return; - - QSGRectangleNode *geometryNode = static_cast<QSGRectangleNode *>(m_node->firstChild()); - Q_ASSERT(!geometryNode || geometryNode->type() == QSGNode::GeometryNodeType); - if (!geometryNode) - return; + qint64 time = m_timer.elapsed(); + if (time >= TotalDuration) + m_timer.restart(); + QSGRectangleNode *geometryNode = static_cast<QSGRectangleNode *>(firstChild()); + Q_ASSERT(geometryNode->type() == QSGNode::GeometryNodeType); const QRectF geometry = geometryNode->rect(); QSGTransformNode *firstNode = static_cast<QSGTransformNode *>(geometryNode->firstChild()); @@ -106,21 +99,69 @@ void QQuickMaterialProgressStripAnimatorJob::updateCurrentTime(int time) } } -void QQuickMaterialProgressStripAnimatorJob::writeBack() +void QQuickMaterialProgressBarNode::sync(QQuickMaterialProgressBar *item) { -} + if (m_indeterminate != item->isIndeterminate()) { + m_indeterminate = item->isIndeterminate(); + QQuickWindow *window = item->window(); + if (m_indeterminate) { + connect(window, &QQuickWindow::frameSwapped, window, &QQuickWindow::update); + connect(window, &QQuickWindow::beforeRendering, this, &QQuickMaterialProgressBarNode::animate); + } else { + disconnect(window, &QQuickWindow::frameSwapped, window, &QQuickWindow::update); + disconnect(window, &QQuickWindow::beforeRendering, this, &QQuickMaterialProgressBarNode::animate); + } + } -void QQuickMaterialProgressStripAnimatorJob::nodeWasDestroyed() -{ - m_node = nullptr; -} + QQuickItemPrivate *d = QQuickItemPrivate::get(item); -void QQuickMaterialProgressStripAnimatorJob::afterNodeSync() -{ - m_node = QQuickItemPrivate::get(m_target)->childContainerNode(); + QRectF bounds = item->boundingRect(); + bounds.setHeight(item->implicitHeight()); + bounds.moveTop((item->height() - bounds.height()) / 2.0); + + QSGRectangleNode *geometryNode = static_cast<QSGRectangleNode *>(firstChild()); + if (!geometryNode) { + geometryNode = item->window()->createRectangleNode(); + geometryNode->setColor(Qt::transparent); + appendChildNode(geometryNode); + } + geometryNode->setRect(bounds); + + const int count = m_indeterminate ? 2 : 1; + const qreal w = m_indeterminate ? 0 : item->progress() * item->width(); + const QRectF rect(0, bounds.y(), w, bounds.height()); + + QSGNode *transformNode = geometryNode->firstChild(); + for (int i = 0; i < count; ++i) { + if (!transformNode) { + transformNode = new QSGTransformNode; + geometryNode->appendChildNode(transformNode); + + QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode(); + rectNode->setAntialiasing(true); + transformNode->appendChildNode(rectNode); + } + Q_ASSERT(transformNode->type() == QSGNode::TransformNodeType); + static_cast<QSGTransformNode *>(transformNode)->setMatrix(QMatrix4x4()); + + QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(transformNode->firstChild()); + Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType); + + rectNode->setRect(rect); + rectNode->setColor(item->color()); + rectNode->update(); + + transformNode = transformNode->nextSibling(); + } + + while (transformNode) { + QSGNode *nextSibling = transformNode->nextSibling(); + delete transformNode; + transformNode = nextSibling; + } } -void QQuickMaterialProgressStripAnimatorJob::moveNode(QSGTransformNode *transformNode, const QRectF &geometry, qreal progress) +void QQuickMaterialProgressBarNode::moveNode(QSGTransformNode *transformNode, const QRectF &geometry, qreal progress) { const qreal value = m_easing.valueForProgress(progress); const qreal x = value * geometry.width(); @@ -138,36 +179,18 @@ void QQuickMaterialProgressStripAnimatorJob::moveNode(QSGTransformNode *transfor rectNode->update(); } -QQuickMaterialStripAnimator::QQuickMaterialStripAnimator(QObject *parent) - : QQuickAnimator(parent) -{ - setLoops(Infinite); - setDuration(TotalDuration); - setEasing(QEasingCurve::OutCubic); -} - -QString QQuickMaterialStripAnimator::propertyName() const -{ - return QString(); -} - -QQuickAnimatorJob *QQuickMaterialStripAnimator::createJob() const -{ - return new QQuickMaterialProgressStripAnimatorJob; -} - -QQuickMaterialProgressStrip::QQuickMaterialProgressStrip(QQuickItem *parent) +QQuickMaterialProgressBar::QQuickMaterialProgressBar(QQuickItem *parent) : QQuickItem(parent), m_color(Qt::black), m_progress(0.0), m_indeterminate(false) { setFlag(ItemHasContents); } -QColor QQuickMaterialProgressStrip::color() const +QColor QQuickMaterialProgressBar::color() const { return m_color; } -void QQuickMaterialProgressStrip::setColor(const QColor &color) +void QQuickMaterialProgressBar::setColor(const QColor &color) { if (color == m_color) return; @@ -176,12 +199,12 @@ void QQuickMaterialProgressStrip::setColor(const QColor &color) update(); } -qreal QQuickMaterialProgressStrip::progress() const +qreal QQuickMaterialProgressBar::progress() const { return m_progress; } -void QQuickMaterialProgressStrip::setProgress(qreal progress) +void QQuickMaterialProgressBar::setProgress(qreal progress) { if (progress == m_progress) return; @@ -190,12 +213,12 @@ void QQuickMaterialProgressStrip::setProgress(qreal progress) update(); } -bool QQuickMaterialProgressStrip::isIndeterminate() const +bool QQuickMaterialProgressBar::isIndeterminate() const { return m_indeterminate; } -void QQuickMaterialProgressStrip::setIndeterminate(bool indeterminate) +void QQuickMaterialProgressBar::setIndeterminate(bool indeterminate) { if (indeterminate == m_indeterminate) return; @@ -204,54 +227,25 @@ void QQuickMaterialProgressStrip::setIndeterminate(bool indeterminate) update(); } -QSGNode *QQuickMaterialProgressStrip::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) +void QQuickMaterialProgressBar::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) { - QQuickItemPrivate *d = QQuickItemPrivate::get(this); - - QRectF bounds = boundingRect(); - bounds.setHeight(implicitHeight()); - bounds.moveTop((height() - bounds.height()) / 2.0); - - if (!oldNode) { - oldNode = window()->createRectangleNode(); - static_cast<QSGRectangleNode *>(oldNode)->setColor(Qt::transparent); - } - static_cast<QSGRectangleNode *>(oldNode)->setRect(bounds); - - const int count = m_indeterminate ? 2 : 1; - const qreal w = m_indeterminate ? 0 : m_progress * width(); - const QRectF rect(0, bounds.y(), w, bounds.height()); - - QSGNode *transformNode = oldNode->firstChild(); - for (int i = 0; i < count; ++i) { - if (!transformNode) { - transformNode = new QSGTransformNode; - oldNode->appendChildNode(transformNode); - - QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode(); - rectNode->setAntialiasing(true); - transformNode->appendChildNode(rectNode); - } - Q_ASSERT(transformNode->type() == QSGNode::TransformNodeType); - static_cast<QSGTransformNode *>(transformNode)->setMatrix(QMatrix4x4()); - - QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(transformNode->firstChild()); - Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType); - - rectNode->setRect(rect); - rectNode->setColor(m_color); - rectNode->update(); - - transformNode = transformNode->nextSibling(); - } + QQuickItem::itemChange(change, data); + if (change == ItemVisibleHasChanged) + update(); +} - while (transformNode) { - QSGNode *nextSibling = transformNode->nextSibling(); - delete transformNode; - transformNode = nextSibling; +QSGNode *QQuickMaterialProgressBar::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *) +{ + QQuickMaterialProgressBarNode *node = static_cast<QQuickMaterialProgressBarNode *>(oldNode); + if (isVisible() && width() > 0 && height() > 0) { + if (!node) + node = new QQuickMaterialProgressBarNode(this); + node->sync(this); + } else { + delete node; + node = nullptr; } - - return oldNode; + return node; } QT_END_NAMESPACE diff --git a/src/imports/controls/material/qquickmaterialprogressstrip_p.h b/src/imports/controls/material/qquickmaterialprogressbar_p.h index f441c09d..0b0b576f 100644 --- a/src/imports/controls/material/qquickmaterialprogressstrip_p.h +++ b/src/imports/controls/material/qquickmaterialprogressbar_p.h @@ -34,8 +34,8 @@ ** ****************************************************************************/ -#ifndef QQUICKMATERIALPROGRESSSTRIP_P_H -#define QQUICKMATERIALPROGRESSSTRIP_P_H +#ifndef QQUICKMATERIALPROGRESSBAR_P_H +#define QQUICKMATERIALPROGRESSBAR_P_H // // W A R N I N G @@ -49,11 +49,10 @@ // #include <QtQuick/qquickitem.h> -#include <QtQuick/private/qquickanimator_p.h> QT_BEGIN_NAMESPACE -class QQuickMaterialProgressStrip : public QQuickItem +class QQuickMaterialProgressBar : public QQuickItem { Q_OBJECT Q_PROPERTY(QColor color READ color WRITE setColor FINAL) @@ -61,7 +60,7 @@ class QQuickMaterialProgressStrip : public QQuickItem Q_PROPERTY(bool indeterminate READ isIndeterminate WRITE setIndeterminate FINAL) public: - QQuickMaterialProgressStrip(QQuickItem *parent = nullptr); + explicit QQuickMaterialProgressBar(QQuickItem *parent = nullptr); QColor color() const; void setColor(const QColor &color); @@ -73,6 +72,7 @@ public: void setIndeterminate(bool indeterminate); protected: + void itemChange(ItemChange change, const ItemChangeData &data) override; QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override; private: @@ -81,21 +81,8 @@ private: bool m_indeterminate; }; -class QQuickMaterialStripAnimator : public QQuickAnimator -{ - Q_OBJECT - -public: - QQuickMaterialStripAnimator(QObject *parent = nullptr); - -protected: - QString propertyName() const override; - QQuickAnimatorJob *createJob() const override; -}; - QT_END_NAMESPACE -QML_DECLARE_TYPE(QQuickMaterialProgressStrip) -QML_DECLARE_TYPE(QQuickMaterialStripAnimator) +QML_DECLARE_TYPE(QQuickMaterialProgressBar) -#endif // QQUICKMATERIALPROGRESSSTRIP_P_H +#endif // QQUICKMATERIALPROGRESSBAR_P_H diff --git a/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp b/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp index 27d2c5a6..bf617488 100644 --- a/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp +++ b/src/imports/controls/material/qtquickcontrols2materialstyleplugin.cpp @@ -38,8 +38,8 @@ #include "qquickmaterialstyle_p.h" #include "qquickmaterialtheme_p.h" -#include "qquickmaterialprogressring_p.h" -#include "qquickmaterialprogressstrip_p.h" +#include "qquickmaterialbusyindicator_p.h" +#include "qquickmaterialprogressbar_p.h" #include "qquickmaterialripple_p.h" #include <QtQuickControls2/private/qquickstyleselector_p.h> @@ -91,11 +91,9 @@ void QtQuickControls2MaterialStylePlugin::initializeEngine(QQmlEngine *engine, c QByteArray import = QByteArray(uri) + ".impl"; qmlRegisterType<QQuickPaddedRectangle>(import, 2, 0, "PaddedRectangle"); qmlRegisterRevision<QQuickPaddedRectangle, 1>(import, 2, 1); - qmlRegisterType<QQuickMaterialProgressRing>(import, 2, 0, "ProgressRing"); - qmlRegisterType<QQuickMaterialProgressStrip>(import, 2, 0, "ProgressStrip"); - qmlRegisterType<QQuickMaterialRingAnimator>(import, 2, 0, "RingAnimator"); + qmlRegisterType<QQuickMaterialBusyIndicator>(import, 2, 0, "BusyIndicatorImpl"); + qmlRegisterType<QQuickMaterialProgressBar>(import, 2, 0, "ProgressBarImpl"); qmlRegisterType<QQuickMaterialRipple>(import, 2, 0, "Ripple"); - qmlRegisterType<QQuickMaterialStripAnimator>(import, 2, 0, "StripAnimator"); qmlRegisterType(typeUrl(QStringLiteral("BoxShadow.qml")), import, 2, 0, "BoxShadow"); qmlRegisterType(typeUrl(QStringLiteral("CheckIndicator.qml")), import, 2, 0, "CheckIndicator"); qmlRegisterType(typeUrl(QStringLiteral("ElevationEffect.qml")), import, 2, 0, "ElevationEffect"); diff --git a/src/imports/controls/qquickbusyindicatorring.cpp b/src/imports/controls/qquickbusyindicatorring.cpp deleted file mode 100644 index d8c035d2..00000000 --- a/src/imports/controls/qquickbusyindicatorring.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qquickbusyindicatorring_p.h" - -#include <QtCore/qset.h> -#include <QtGui/qpainter.h> -#include <QtQuick/private/qquickitem_p.h> -#include <QtQuick/qsgnode.h> -#include <QtQuick/qquickwindow.h> -#include <QtQuick/qsgrectanglenode.h> - -QT_BEGIN_NAMESPACE - -class QQuickBusyIndicatorAnimatorJob : public QQuickAnimatorJob -{ -public: - QQuickBusyIndicatorAnimatorJob(); - ~QQuickBusyIndicatorAnimatorJob(); - - void initialize(QQuickAnimatorController *controller) override; - void updateCurrentTime(int time) override; - void writeBack() override; - void nodeWasDestroyed() override; - void afterNodeSync() override; - -private: - QSGNode *m_node; -}; - -static const int circles = 10; -static const int animationDuration = 100 * circles * 2; - -QQuickBusyIndicatorRing::QQuickBusyIndicatorRing(QQuickItem *parent) : - QQuickItem(parent) -{ - setFlag(QQuickItem::ItemHasContents); - setImplicitWidth(116); - setImplicitHeight(116); -} - -QQuickBusyIndicatorRing::~QQuickBusyIndicatorRing() -{ -} - -static QPointF moveBy(const QPointF &pos, qreal rotation, qreal distance) -{ - return pos - QTransform().rotate(rotation).map(QPointF(0, distance)); -} - -QSGNode *QQuickBusyIndicatorRing::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *) -{ - QQuickItemPrivate *d = QQuickItemPrivate::get(this); - - if (!oldNode) { - oldNode = window()->createRectangleNode(); - static_cast<QSGRectangleNode *>(oldNode)->setColor(Qt::transparent); - } - static_cast<QSGRectangleNode *>(oldNode)->setRect(boundingRect()); - - QSGTransformNode *rootTransformNode = static_cast<QSGTransformNode *>(oldNode->firstChild()); - if (!rootTransformNode) { - rootTransformNode = new QSGTransformNode; - oldNode->appendChildNode(rootTransformNode); - } - Q_ASSERT(rootTransformNode->type() == QSGNode::TransformNodeType); - - const qreal w = width(); - const qreal h = height(); - const qreal sz = qMin(w, h); - const qreal dx = (w - sz) / 2; - const qreal dy = (h - sz) / 2; - const int circleRadius = sz / 12; - const QColor color(0x35, 0x36, 0x37); - - QSGTransformNode *transformNode = static_cast<QSGTransformNode *>(rootTransformNode->firstChild()); - for (int i = 0; i < circles; ++i) { - if (!transformNode) { - transformNode = new QSGTransformNode; - rootTransformNode->appendChildNode(transformNode); - - QSGOpacityNode *opacityNode = new QSGOpacityNode; - transformNode->appendChildNode(opacityNode); - - QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode(); - rectNode->setAntialiasing(true); - rectNode->setColor(color); - rectNode->setPenColor(color); - opacityNode->appendChildNode(rectNode); - } - - QSGNode *opacityNode = transformNode->firstChild(); - Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType); - - QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild()); - Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType); - - QPointF pos = QPointF(sz / 2 - circleRadius, sz / 2 - circleRadius); - pos = moveBy(pos, 360 / circles * i, sz / 2 - circleRadius); - - QMatrix4x4 m; - m.translate(dx + pos.x(), dy + pos.y()); - transformNode->setMatrix(m); - - rectNode->setRect(QRectF(QPointF(), QSizeF(circleRadius * 2, circleRadius * 2))); - rectNode->setRadius(circleRadius); - rectNode->update(); - - transformNode = static_cast<QSGTransformNode *>(transformNode->nextSibling()); - } - - return oldNode; -} - -QQuickBusyIndicatorAnimator::QQuickBusyIndicatorAnimator(QObject *parent) : - QQuickAnimator(parent) -{ - setDuration(animationDuration); - setLoops(QQuickAnimator::Infinite); -} - -QString QQuickBusyIndicatorAnimator::propertyName() const -{ - return QString(); -} - -QQuickAnimatorJob *QQuickBusyIndicatorAnimator::createJob() const -{ - return new QQuickBusyIndicatorAnimatorJob; -} - -QQuickBusyIndicatorAnimatorJob::QQuickBusyIndicatorAnimatorJob() : m_node(nullptr) -{ -} - -QQuickBusyIndicatorAnimatorJob::~QQuickBusyIndicatorAnimatorJob() -{ -} - -void QQuickBusyIndicatorAnimatorJob::initialize(QQuickAnimatorController *controller) -{ - QQuickAnimatorJob::initialize(controller); - m_node = QQuickItemPrivate::get(m_target)->childContainerNode(); -} - -void QQuickBusyIndicatorAnimatorJob::updateCurrentTime(int time) -{ - if (!m_node) - return; - - QSGRectangleNode *rootRectNode = static_cast<QSGRectangleNode *>(m_node->firstChild()); - if (!rootRectNode) - return; - - Q_ASSERT(rootRectNode->type() == QSGNode::GeometryNodeType); - - QSGTransformNode *rootTransformNode = static_cast<QSGTransformNode*>(rootRectNode->firstChild()); - Q_ASSERT(rootTransformNode->type() == QSGNode::TransformNodeType); - - const qreal percentageComplete = time / qreal(animationDuration); - const qreal firstPhaseProgress = percentageComplete <= 0.5 ? percentageComplete * 2 : 0; - const qreal secondPhaseProgress = percentageComplete > 0.5 ? (percentageComplete - 0.5) * 2 : 0; - - QSGTransformNode *transformNode = static_cast<QSGTransformNode*>(rootTransformNode->firstChild()); - const QColor color(0x35, 0x36, 0x37); - const QColor transparent(Qt::transparent); - Q_ASSERT(transformNode->type() == QSGNode::TransformNodeType); - for (int i = 0; i < circles; ++i) { - QSGOpacityNode *opacityNode = static_cast<QSGOpacityNode*>(transformNode->firstChild()); - Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType); - - QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode*>(opacityNode->firstChild()); - Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType); - - const bool fill = (firstPhaseProgress > qreal(i) / circles) || (secondPhaseProgress > 0 && secondPhaseProgress < qreal(i) / circles); - rectNode->setPenWidth(fill ? 0 : 1); - rectNode->setColor(fill ? color : transparent); - rectNode->update(); - - transformNode = static_cast<QSGTransformNode*>(transformNode->nextSibling()); - } -} - -void QQuickBusyIndicatorAnimatorJob::writeBack() -{ -} - -void QQuickBusyIndicatorAnimatorJob::nodeWasDestroyed() -{ - m_node = nullptr; -} - -void QQuickBusyIndicatorAnimatorJob::afterNodeSync() -{ - m_node = QQuickItemPrivate::get(m_target)->childContainerNode(); -} - -QT_END_NAMESPACE diff --git a/src/imports/controls/qquickdefaultbusyindicator.cpp b/src/imports/controls/qquickdefaultbusyindicator.cpp new file mode 100644 index 00000000..5b952476 --- /dev/null +++ b/src/imports/controls/qquickdefaultbusyindicator.cpp @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickdefaultbusyindicator_p.h" + +#include <QtCore/qset.h> +#include <QtCore/qelapsedtimer.h> +#include <QtGui/qpainter.h> +#include <QtQuick/private/qquickitem_p.h> +#include <QtQuick/qquickwindow.h> +#include <QtQuick/qsgnode.h> + +QT_BEGIN_NAMESPACE + +static const int CircleCount = 10; +static const int TotalDuration = 100 * CircleCount * 2; +static const QRgb TransparentColor = 0x00000000; +static const QRgb FillColor = 0xFF353637; + +static QPointF moveCircle(const QPointF &pos, qreal rotation, qreal distance) +{ + return pos - QTransform().rotate(rotation).map(QPointF(0, distance)); +} + +class QQuickDefaultBusyIndicatorNode : public QObject, public QSGNode +{ +public: + QQuickDefaultBusyIndicatorNode(QQuickDefaultBusyIndicator *item); + + int elapsed() const; + + void animate(); + void sync(QQuickDefaultBusyIndicator *item); + +private: + int m_offset; + QElapsedTimer m_timer; +}; + +QQuickDefaultBusyIndicatorNode::QQuickDefaultBusyIndicatorNode(QQuickDefaultBusyIndicator *item) + : m_offset(item->elapsed()) +{ + QQuickWindow *window = item->window(); + connect(window, &QQuickWindow::frameSwapped, window, &QQuickWindow::update); + connect(window, &QQuickWindow::beforeRendering, this, &QQuickDefaultBusyIndicatorNode::animate); + + for (int i = 0; i < CircleCount; ++i) { + QSGTransformNode *transformNode = new QSGTransformNode; + appendChildNode(transformNode); + + QQuickItemPrivate *d = QQuickItemPrivate::get(item); + QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode(); + rectNode->setAntialiasing(true); + transformNode->appendChildNode(rectNode); + } + + m_timer.restart(); +} + +int QQuickDefaultBusyIndicatorNode::elapsed() const +{ + return m_timer.elapsed() + m_offset; +} + +void QQuickDefaultBusyIndicatorNode::animate() +{ + qint64 time = m_timer.elapsed() + m_offset; + if (time >= TotalDuration) { + m_timer.restart(); + m_offset = 0; + } + + const qreal percentageComplete = time / qreal(TotalDuration); + const qreal firstPhaseProgress = percentageComplete <= 0.5 ? percentageComplete * 2 : 0; + const qreal secondPhaseProgress = percentageComplete > 0.5 ? (percentageComplete - 0.5) * 2 : 0; + + QSGTransformNode *transformNode = static_cast<QSGTransformNode*>(firstChild()); + Q_ASSERT(transformNode->type() == QSGNode::TransformNodeType); + for (int i = 0; i < CircleCount; ++i) { + QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode*>(transformNode->firstChild()); + Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType); + + const bool fill = (firstPhaseProgress > qreal(i) / CircleCount) || (secondPhaseProgress > 0 && secondPhaseProgress < qreal(i) / CircleCount); + rectNode->setColor(QColor::fromRgba(fill ? FillColor : TransparentColor)); + rectNode->setPenWidth(fill ? 0 : 1); + rectNode->update(); + + transformNode = static_cast<QSGTransformNode*>(transformNode->nextSibling()); + } +} + +void QQuickDefaultBusyIndicatorNode::sync(QQuickDefaultBusyIndicator *item) +{ + const qreal w = item->width(); + const qreal h = item->height(); + const qreal sz = qMin(w, h); + const qreal dx = (w - sz) / 2; + const qreal dy = (h - sz) / 2; + const int circleRadius = sz / 12; + + QSGTransformNode *transformNode = static_cast<QSGTransformNode *>(firstChild()); + for (int i = 0; i < CircleCount; ++i) { + Q_ASSERT(transformNode->type() == QSGNode::TransformNodeType); + + QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(transformNode->firstChild()); + Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType); + + QPointF pos = QPointF(sz / 2 - circleRadius, sz / 2 - circleRadius); + pos = moveCircle(pos, 360 / CircleCount * i, sz / 2 - circleRadius); + + QMatrix4x4 m; + m.translate(dx + pos.x(), dy + pos.y()); + transformNode->setMatrix(m); + + rectNode->setRect(QRectF(QPointF(), QSizeF(circleRadius * 2, circleRadius * 2))); + rectNode->setRadius(circleRadius); + + transformNode = static_cast<QSGTransformNode *>(transformNode->nextSibling()); + } +} + +QQuickDefaultBusyIndicator::QQuickDefaultBusyIndicator(QQuickItem *parent) : + QQuickItem(parent), m_elapsed(0) +{ + setFlag(ItemHasContents); +} + +int QQuickDefaultBusyIndicator::elapsed() const +{ + return m_elapsed; +} + +void QQuickDefaultBusyIndicator::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) +{ + QQuickItem::itemChange(change, data); + if (change == ItemVisibleHasChanged) + update(); +} + +QSGNode *QQuickDefaultBusyIndicator::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *) +{ + QQuickDefaultBusyIndicatorNode *node = static_cast<QQuickDefaultBusyIndicatorNode *>(oldNode); + if (isVisible() && width() > 0 && height() > 0) { + if (!node) + node = new QQuickDefaultBusyIndicatorNode(this); + node->sync(this); + } else { + m_elapsed = node ? node->elapsed() : 0; + delete node; + node = nullptr; + } + return node; +} + +QT_END_NAMESPACE diff --git a/src/imports/controls/qquickbusyindicatorring_p.h b/src/imports/controls/qquickdefaultbusyindicator_p.h index ceac0471..6147b8e3 100644 --- a/src/imports/controls/qquickbusyindicatorring_p.h +++ b/src/imports/controls/qquickdefaultbusyindicator_p.h @@ -34,8 +34,8 @@ ** ****************************************************************************/ -#ifndef QQUICKBUSYINDICATORRING_P_H -#define QQUICKBUSYINDICATORRING_P_H +#ifndef QQUICKDEFAULTBUSYINDICATOR_P_H +#define QQUICKDEFAULTBUSYINDICATOR_P_H // // W A R N I N G @@ -49,34 +49,28 @@ // #include <QtQuick/qquickitem.h> -#include <QtQuick/private/qquickanimatorjob_p.h> QT_BEGIN_NAMESPACE -class QQuickBusyIndicatorRing : public QQuickItem +class QQuickDefaultBusyIndicator : public QQuickItem { Q_OBJECT public: - explicit QQuickBusyIndicatorRing(QQuickItem *parent = nullptr); - ~QQuickBusyIndicatorRing(); + explicit QQuickDefaultBusyIndicator(QQuickItem *parent = nullptr); + + int elapsed() const; protected: + void itemChange(ItemChange change, const ItemChangeData &data) override; QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override; -}; - -class QQuickBusyIndicatorAnimator : public QQuickAnimator -{ -public: - QQuickBusyIndicatorAnimator(QObject *parent = nullptr); -protected: - QString propertyName() const override; - QQuickAnimatorJob *createJob() const override; +private: + int m_elapsed; }; QT_END_NAMESPACE -QML_DECLARE_TYPE(QQuickBusyIndicatorRing) +QML_DECLARE_TYPE(QQuickDefaultBusyIndicator) -#endif // QQUICKBUSYINDICATORRING_P_H +#endif // QQUICKDEFAULTBUSYINDICATOR_P_H diff --git a/src/imports/controls/qquickdefaultprogressbar.cpp b/src/imports/controls/qquickdefaultprogressbar.cpp new file mode 100644 index 00000000..a626bb32 --- /dev/null +++ b/src/imports/controls/qquickdefaultprogressbar.cpp @@ -0,0 +1,277 @@ +/**************************************************************************** +** +** Copyright (C) 2016 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL3$ +** 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 http://www.qt.io/terms-conditions. For further +** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free +** Software Foundation and appearing in the file LICENSE.GPL included in +** the packaging of this file. Please review the following information to +** ensure the GNU General Public License version 2.0 requirements will be +** met: http://www.gnu.org/licenses/gpl-2.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qquickdefaultprogressbar_p.h" + +#include <QtCore/qeasingcurve.h> +#include <QtCore/qelapsedtimer.h> +#include <QtQuick/private/qquickitem_p.h> +#include <QtQuick/private/qsgadaptationlayer_p.h> + +QT_BEGIN_NAMESPACE + +static const int Blocks = 4; +static const int BlockWidth = 16; +static const int BlockRestingSpacing = 4; +static const int BlockMovingSpacing = 48; +static const int BlockSpan = Blocks * (BlockWidth + BlockRestingSpacing) - BlockRestingSpacing; +static const int TotalDuration = 4000; +static const int SecondPhaseStart = TotalDuration * 0.4; +static const int ThirdPhaseStart = TotalDuration * 0.6; +static const QRgb FillColor = 0x353637; + +static inline qreal blockStartX(int blockIndex) +{ + return ((blockIndex + 1) * -BlockWidth) - (blockIndex * BlockMovingSpacing); +} + +static inline qreal blockRestX(int blockIndex, qreal availableWidth) +{ + const qreal spanRightEdgePos = availableWidth / 2 + BlockSpan / 2; + return spanRightEdgePos - (blockIndex + 1) * BlockWidth - (blockIndex * BlockRestingSpacing); +} + +static inline qreal blockEndX(int blockIndex, qreal availableWidth) +{ + return availableWidth - blockStartX(Blocks - 1 - blockIndex) - BlockWidth; +} + +class QQuickDefaultProgressBarNode : public QObject, public QSGTransformNode +{ +public: + QQuickDefaultProgressBarNode(QQuickDefaultProgressBar *item); + + void animate(); + void sync(QQuickDefaultProgressBar *item); + +private: + bool m_indeterminate; + qreal m_pixelsPerSecond; + QElapsedTimer m_timer; +}; + +QQuickDefaultProgressBarNode::QQuickDefaultProgressBarNode(QQuickDefaultProgressBar *item) + : m_indeterminate(false), m_pixelsPerSecond(item->width()) +{ + m_timer.start(); +} + +void QQuickDefaultProgressBarNode::animate() +{ + qint64 time = m_timer.elapsed(); + if (time >= TotalDuration) + m_timer.restart(); + + QSGTransformNode *transformNode = static_cast<QSGTransformNode*>(firstChild()); + for (int i = 0; i < Blocks; ++i) { + Q_ASSERT(transformNode->type() == QSGNode::TransformNodeType); + + QMatrix4x4 m; + const qreal restX = blockRestX(i, m_pixelsPerSecond); + const qreal timeInSeconds = time / 1000.0; + + if (time < SecondPhaseStart) { + // Move into the resting position for the first phase. + QEasingCurve easingCurve(QEasingCurve::InQuad); + const qreal easedCompletion = easingCurve.valueForProgress(time / qreal(SecondPhaseStart)); + const qreal distance = m_pixelsPerSecond * (easedCompletion * (SecondPhaseStart / 1000.0)); + const qreal position = blockStartX(i) + distance; + const qreal destination = restX; + m.translate(qMin(position, destination), 0); + } else if (time < ThirdPhaseStart) { + // Stay in the same position for the second phase. + m.translate(restX, 0); + } else { + // Move out of view for the third phase. + const int thirdPhaseSubKickoff = (BlockMovingSpacing / m_pixelsPerSecond) * 1000; + const int subphase = (time - ThirdPhaseStart) / thirdPhaseSubKickoff; + // If we're not at this subphase yet, don't try to animate movement, + // because it will be incorrect. + if (subphase < i) + return; + + const qreal timeSinceSecondPhase = timeInSeconds - (ThirdPhaseStart / 1000.0); + // We only want to start keeping track of time once our subphase has started, + // otherwise we move too much because we account for time that has already elapsed. + // For example, if we were 60 milliseconds into the third subphase: + // + // 0 ..... 1 ..... 2 ... + // 100 100 60 + // + // i == 0, timeSinceOurKickoff == 260 + // i == 1, timeSinceOurKickoff == 160 + // i == 2, timeSinceOurKickoff == 60 + const qreal timeSinceOurKickoff = timeSinceSecondPhase - (thirdPhaseSubKickoff / 1000.0 * i); + const qreal position = restX + (m_pixelsPerSecond * (timeSinceOurKickoff)); + const qreal destination = blockEndX(i, m_pixelsPerSecond); + m.translate(qMin(position, destination), 0); + } + + transformNode->setMatrix(m); + + transformNode = static_cast<QSGTransformNode*>(transformNode->nextSibling()); + } +} + +void QQuickDefaultProgressBarNode::sync(QQuickDefaultProgressBar *item) +{ + m_pixelsPerSecond = item->width(); + if (m_indeterminate != item->isIndeterminate()) { + m_indeterminate = item->isIndeterminate(); + QQuickWindow *window = item->window(); + if (m_indeterminate) { + connect(window, &QQuickWindow::frameSwapped, window, &QQuickWindow::update); + connect(window, &QQuickWindow::beforeRendering, this, &QQuickDefaultProgressBarNode::animate); + } else { + disconnect(window, &QQuickWindow::frameSwapped, window, &QQuickWindow::update); + disconnect(window, &QQuickWindow::beforeRendering, this, &QQuickDefaultProgressBarNode::animate); + } + } + + QQuickItemPrivate *d = QQuickItemPrivate::get(item); + + QMatrix4x4 m; + m.translate(0, (item->height() - item->implicitHeight()) / 2); + setMatrix(m); + + if (item->isIndeterminate()) { + if (childCount() != Blocks) { + // This was previously a regular progress bar; remove the old nodes. + removeAllChildNodes(); + } + + QSGTransformNode *transformNode = static_cast<QSGTransformNode*>(firstChild()); + for (int i = 0; i < Blocks; ++i) { + if (!transformNode) { + transformNode = new QSGTransformNode; + appendChildNode(transformNode); + } + + QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode*>(transformNode->firstChild()); + if (!rectNode) { + rectNode = d->sceneGraphContext()->createInternalRectangleNode(); + rectNode->setColor(FillColor); + transformNode->appendChildNode(rectNode); + } + + QMatrix4x4 m; + m.translate(blockStartX(i), 0); + transformNode->setMatrix(m); + + rectNode->setRect(QRectF(QPointF(0, 0), QSizeF(BlockWidth, item->implicitHeight()))); + rectNode->update(); + + transformNode = static_cast<QSGTransformNode *>(transformNode->nextSibling()); + } + } else { + if (childCount() > 1) { + // This was previously an indeterminate progress bar; remove the old nodes. + removeAllChildNodes(); + } + + QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(firstChild()); + if (!rectNode) { + rectNode = d->sceneGraphContext()->createInternalRectangleNode(); + rectNode->setColor(FillColor); + appendChildNode(rectNode); + } + + rectNode->setRect(QRectF(QPointF(0, 0), QSizeF(item->progress() * item->width(), item->implicitHeight()))); + rectNode->update(); + } +} + +QQuickDefaultProgressBar::QQuickDefaultProgressBar(QQuickItem *parent) : + QQuickItem(parent), + m_progress(0), + m_indeterminate(false) +{ + setFlag(ItemHasContents); +} + +qreal QQuickDefaultProgressBar::progress() const +{ + return m_progress; +} + +void QQuickDefaultProgressBar::setProgress(qreal progress) +{ + if (progress == m_progress) + return; + + m_progress = progress; + update(); + emit progressChanged(); +} + +bool QQuickDefaultProgressBar::isIndeterminate() const +{ + return m_indeterminate; +} + +void QQuickDefaultProgressBar::setIndeterminate(bool indeterminate) +{ + if (indeterminate == m_indeterminate) + return; + + m_indeterminate = indeterminate; + setClip(m_indeterminate); + update(); + emit indeterminateChanged(); +} + +void QQuickDefaultProgressBar::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) +{ + QQuickItem::itemChange(change, data); + if (change == ItemVisibleHasChanged) + update(); +} + +QSGNode *QQuickDefaultProgressBar::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *) +{ + QQuickDefaultProgressBarNode *node = static_cast<QQuickDefaultProgressBarNode *>(oldNode); + if (isVisible() && width() > 0 && height() > 0) { + if (!node) + node = new QQuickDefaultProgressBarNode(this); + node->sync(this); + } else { + delete node; + node = nullptr; + } + return node; +} + +QT_END_NAMESPACE diff --git a/src/imports/controls/qquickprogressstrip_p.h b/src/imports/controls/qquickdefaultprogressbar_p.h index d2e297f5..ec228eee 100644 --- a/src/imports/controls/qquickprogressstrip_p.h +++ b/src/imports/controls/qquickdefaultprogressbar_p.h @@ -34,8 +34,8 @@ ** ****************************************************************************/ -#ifndef QQUICKPROGRESSSTRIP_P_H -#define QQUICKPROGRESSSTRIP_P_H +#ifndef QQUICKDEFAULTPROGRESSBAR_P_H +#define QQUICKDEFAULTPROGRESSBAR_P_H // // W A R N I N G @@ -49,19 +49,17 @@ // #include <QtQuick/qquickitem.h> -#include <QtQuick/private/qquickanimatorjob_p.h> QT_BEGIN_NAMESPACE -class QQuickProgressStrip : public QQuickItem +class QQuickDefaultProgressBar : public QQuickItem { Q_OBJECT Q_PROPERTY(bool indeterminate READ isIndeterminate WRITE setIndeterminate NOTIFY indeterminateChanged FINAL) Q_PROPERTY(qreal progress READ progress WRITE setProgress NOTIFY progressChanged FINAL) public: - explicit QQuickProgressStrip(QQuickItem *parent = nullptr); - ~QQuickProgressStrip(); + explicit QQuickDefaultProgressBar(QQuickItem *parent = nullptr); bool isIndeterminate() const; void setIndeterminate(bool indeterminate); @@ -74,6 +72,7 @@ Q_SIGNALS: void indeterminateChanged(); protected: + void itemChange(ItemChange change, const ItemChangeData &data) override; QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override; private: @@ -81,16 +80,8 @@ private: bool m_indeterminate; }; -class QQuickProgressAnimator : public QQuickAnimator -{ -public: - QQuickProgressAnimator(QObject *parent = nullptr); - -protected: - QString propertyName() const override; - QQuickAnimatorJob *createJob() const override; -}; - QT_END_NAMESPACE -#endif // QQUICKPROGRESSSTRIP_P_H +QML_DECLARE_TYPE(QQuickDefaultProgressBar) + +#endif // QQUICKDEFAULTPROGRESSBAR_P_H diff --git a/src/imports/controls/qquickprogressstrip.cpp b/src/imports/controls/qquickprogressstrip.cpp deleted file mode 100644 index 33a21848..00000000 --- a/src/imports/controls/qquickprogressstrip.cpp +++ /dev/null @@ -1,315 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: http://www.qt.io/licensing/ -** -** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL3$ -** 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 http://www.qt.io/terms-conditions. For further -** information use the contact form at http://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.LGPLv3 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.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 later as published by the Free -** Software Foundation and appearing in the file LICENSE.GPL included in -** the packaging of this file. Please review the following information to -** ensure the GNU General Public License version 2.0 requirements will be -** met: http://www.gnu.org/licenses/gpl-2.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qquickprogressstrip_p.h" - -#include <QtQuick/private/qquickitem_p.h> -#include <QtQuick/qsgrectanglenode.h> - -QT_BEGIN_NAMESPACE - -class QQuickProgressAnimatorJob : public QQuickAnimatorJob -{ -public: - QQuickProgressAnimatorJob(); - ~QQuickProgressAnimatorJob(); - - void initialize(QQuickAnimatorController *controller) override; - void afterNodeSync() override; - void updateCurrentTime(int time) override; - void writeBack() override; - void nodeWasDestroyed() override; - -private: - QSGNode *m_node; -}; - -QQuickProgressStrip::QQuickProgressStrip(QQuickItem *parent) : - QQuickItem(parent), - m_progress(0), - m_indeterminate(false) -{ - setFlag(QQuickItem::ItemHasContents); -} - -QQuickProgressStrip::~QQuickProgressStrip() -{ -} - -qreal QQuickProgressStrip::progress() const -{ - return m_progress; -} - -void QQuickProgressStrip::setProgress(qreal progress) -{ - if (progress == m_progress) - return; - - m_progress = progress; - update(); - emit progressChanged(); -} - -bool QQuickProgressStrip::isIndeterminate() const -{ - return m_indeterminate; -} - -void QQuickProgressStrip::setIndeterminate(bool indeterminate) -{ - if (indeterminate == m_indeterminate) - return; - - m_indeterminate = indeterminate; - setClip(m_indeterminate); - update(); - emit indeterminateChanged(); -} - -static const int blocks = 4; -static const int blockWidth = 16; -static const int blockRestingSpacing = 4; -static const int blockMovingSpacing = 48; -static const int blockSpan = blocks * (blockWidth + blockRestingSpacing) - blockRestingSpacing; -static const int animationDuration = 4000; -static const int secondPhaseStart = animationDuration * 0.4; -static const int thirdPhaseStart = animationDuration * 0.6; - -static inline qreal blockStartX(int blockIndex) -{ - return ((blockIndex + 1) * -blockWidth) - (blockIndex * blockMovingSpacing); -} - -static inline qreal blockRestX(int blockIndex, qreal availableWidth) -{ - const qreal spanRightEdgePos = availableWidth / 2 + blockSpan / 2; - return spanRightEdgePos - (blockIndex + 1) * blockWidth - (blockIndex * blockRestingSpacing); -} - -static inline qreal blockEndX(int blockIndex, qreal availableWidth) -{ - return availableWidth - blockStartX(blocks - 1 - blockIndex) - blockWidth; -} - -QSGNode *QQuickProgressStrip::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *) -{ - QQuickItemPrivate *d = QQuickItemPrivate::get(this); - - if (!oldNode) { - oldNode = window()->createRectangleNode(); - static_cast<QSGRectangleNode *>(oldNode)->setColor(Qt::transparent); - } - static_cast<QSGRectangleNode *>(oldNode)->setRect(boundingRect()); - - QSGTransformNode *rootTransformNode = static_cast<QSGTransformNode *>(oldNode->firstChild()); - if (!rootTransformNode) { - rootTransformNode = new QSGTransformNode; - oldNode->appendChildNode(rootTransformNode); - } - Q_ASSERT(rootTransformNode->type() == QSGNode::TransformNodeType); - - const qreal y = (height() - implicitHeight()) / 2; - const QColor color(0x35, 0x36, 0x37); - if (m_indeterminate) { - if (rootTransformNode->childCount() != blocks) { - // This was previously a regular progress bar; remove the old nodes. - rootTransformNode->removeAllChildNodes(); - } - - QSGTransformNode *transformNode = static_cast<QSGTransformNode*>(rootTransformNode->firstChild()); - for (int i = 0; i < blocks; ++i) { - if (!transformNode) { - transformNode = new QSGTransformNode; - rootTransformNode->appendChildNode(transformNode); - } - - QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode*>(transformNode->firstChild()); - if (!rectNode) { - rectNode = d->sceneGraphContext()->createInternalRectangleNode(); - rectNode->setColor(color); - transformNode->appendChildNode(rectNode); - } - - QMatrix4x4 m; - m.translate(blockStartX(i), 0); - transformNode->setMatrix(m); - - rectNode->setRect(QRectF(QPointF(0, y), QSizeF(blockWidth, implicitHeight()))); - rectNode->update(); - - transformNode = static_cast<QSGTransformNode *>(transformNode->nextSibling()); - } - } else { - if (rootTransformNode->childCount() > 1) { - // This was previously an indeterminate progress bar; remove the old nodes. - rootTransformNode->removeAllChildNodes(); - } - - QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(rootTransformNode->firstChild()); - if (!rectNode) { - rectNode = d->sceneGraphContext()->createInternalRectangleNode(); - rectNode->setColor(color); - rootTransformNode->appendChildNode(rectNode); - } - - rectNode->setRect(QRectF(QPointF(0, y), QSizeF(m_progress * width(), implicitHeight()))); - rectNode->update(); - } - - return oldNode; -} - -QQuickProgressAnimator::QQuickProgressAnimator(QObject *parent) : - QQuickAnimator(parent) -{ - setDuration(animationDuration); - setLoops(QQuickAnimator::Infinite); -} - -QString QQuickProgressAnimator::propertyName() const -{ - return QString(); -} - -QQuickAnimatorJob *QQuickProgressAnimator::createJob() const -{ - return new QQuickProgressAnimatorJob; -} - -QQuickProgressAnimatorJob::QQuickProgressAnimatorJob() : - m_node(nullptr) -{ -} - -QQuickProgressAnimatorJob::~QQuickProgressAnimatorJob() -{ -} - -void QQuickProgressAnimatorJob::initialize(QQuickAnimatorController *controller) -{ - QQuickAnimatorJob::initialize(controller); - m_node = QQuickItemPrivate::get(m_target)->childContainerNode(); -} - -void QQuickProgressAnimatorJob::afterNodeSync() -{ - m_node = QQuickItemPrivate::get(m_target)->childContainerNode(); -} - -void QQuickProgressAnimatorJob::updateCurrentTime(int time) -{ - if (!m_node) - return; - - QSGRectangleNode *rootRectNode = static_cast<QSGRectangleNode *>(m_node->firstChild()); - if (!rootRectNode) - return; - Q_ASSERT(rootRectNode->type() == QSGNode::GeometryNodeType); - - QSGTransformNode *rootTransformNode = static_cast<QSGTransformNode*>(rootRectNode->firstChild()); - Q_ASSERT(rootTransformNode->type() == QSGNode::TransformNodeType); - - QSGTransformNode *transformNode = static_cast<QSGTransformNode*>(rootTransformNode->firstChild()); - // This function can be called without the relevant nodes having been created yet, - // which can happen if you set indeterminate to true at runtime. - if (!transformNode || transformNode->type() != QSGNode::TransformNodeType) - return; - - const qreal pixelsPerSecond = rootRectNode->rect().width(); - - for (int i = 0; i < blocks; ++i) { - QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode*>(transformNode->firstChild()); - Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType); - - QMatrix4x4 m; - const qreal restX = blockRestX(i, rootRectNode->rect().width()); - const qreal timeInSeconds = time / 1000.0; - - if (time < secondPhaseStart) { - // Move into the resting position for the first phase. - QEasingCurve easingCurve(QEasingCurve::InQuad); - const qreal easedCompletion = easingCurve.valueForProgress(time / qreal(secondPhaseStart)); - const qreal distance = pixelsPerSecond * (easedCompletion * (secondPhaseStart / 1000.0)); - const qreal position = blockStartX(i) + distance; - const qreal destination = restX; - m.translate(qMin(position, destination), 0); - } else if (time < thirdPhaseStart) { - // Stay in the same position for the second phase. - m.translate(restX, 0); - } else { - // Move out of view for the third phase. - const int thirdPhaseSubKickoff = (blockMovingSpacing / pixelsPerSecond) * 1000; - const int subphase = (time - thirdPhaseStart) / thirdPhaseSubKickoff; - // If we're not at this subphase yet, don't try to animate movement, - // because it will be incorrect. - if (subphase < i) - return; - - const qreal timeSinceSecondPhase = timeInSeconds - (thirdPhaseStart / 1000.0); - // We only want to start keeping track of time once our subphase has started, - // otherwise we move too much because we account for time that has already elapsed. - // For example, if we were 60 milliseconds into the third subphase: - // - // 0 ..... 1 ..... 2 ... - // 100 100 60 - // - // i == 0, timeSinceOurKickoff == 260 - // i == 1, timeSinceOurKickoff == 160 - // i == 2, timeSinceOurKickoff == 60 - const qreal timeSinceOurKickoff = timeSinceSecondPhase - (thirdPhaseSubKickoff / 1000.0 * i); - const qreal position = restX + (pixelsPerSecond * (timeSinceOurKickoff)); - const qreal destination = blockEndX(i, rootRectNode->rect().width()); - m.translate(qMin(position, destination), 0); - } - - transformNode->setMatrix(m); - rectNode->update(); - - transformNode = static_cast<QSGTransformNode*>(transformNode->nextSibling()); - } -} - -void QQuickProgressAnimatorJob::writeBack() -{ -} - -void QQuickProgressAnimatorJob::nodeWasDestroyed() -{ - m_node = nullptr; -} - -QT_END_NAMESPACE diff --git a/src/imports/controls/qtquickcontrols2plugin.cpp b/src/imports/controls/qtquickcontrols2plugin.cpp index 5b8868fe..6802171f 100644 --- a/src/imports/controls/qtquickcontrols2plugin.cpp +++ b/src/imports/controls/qtquickcontrols2plugin.cpp @@ -41,12 +41,16 @@ #include <QtQuickControls2/private/qquickstyleselector_p.h> #include <QtQuickControls2/private/qquickcolorimageprovider_p.h> #include <QtQuickTemplates2/private/qquickbuttongroup_p.h> +#include <QtQuickTemplates2/private/qquickdial_p.h> +#include <QtQuickTemplates2/private/qquickrangeslider_p.h> +#include <QtQuickTemplates2/private/qquickslider_p.h> +#include <QtQuickTemplates2/private/qquicktumbler_p.h> #include <QtQuickControls2/private/qquicktumblerview_p.h> -#include "qquickbusyindicatorring_p.h" +#include "qquickdefaultbusyindicator_p.h" +#include "qquickdefaultprogressbar_p.h" #include "qquickdefaultstyle_p.h" #include "qquickdialring_p.h" -#include "qquickprogressstrip_p.h" static inline void initResources() { @@ -137,6 +141,12 @@ void QtQuickControls2Plugin::registerTypes(const char *uri) qmlRegisterType(selector.select(QStringLiteral("MenuSeparator.qml")), uri, 2, 1, "MenuSeparator"); qmlRegisterType(selector.select(QStringLiteral("RoundButton.qml")), uri, 2, 1, "RoundButton"); qmlRegisterType(selector.select(QStringLiteral("ToolSeparator.qml")), uri, 2, 1, "ToolSeparator"); + + // QtQuick.Controls 2.2 (Qt 5.9) + qmlRegisterRevision<QQuickDial, 2>(uri, 2, 2); + qmlRegisterRevision<QQuickRangeSlider, 2>(uri, 2, 2); + qmlRegisterRevision<QQuickSlider, 2>(uri, 2, 2); + qmlRegisterRevision<QQuickTumbler, 2>(uri, 2, 2); } static QObject *styleSingleton(QQmlEngine *engine, QJSEngine *scriptEngine) @@ -153,10 +163,8 @@ void QtQuickControls2Plugin::initializeEngine(QQmlEngine *engine, const char *ur engine->addImageProvider(QStringLiteral("default"), new QQuickColorImageProvider(QStringLiteral(":/qt-project.org/imports/QtQuick/Controls.2/images"))); const QByteArray import = QByteArray(uri) + ".impl"; - qmlRegisterType<QQuickBusyIndicatorRing>(import, 2, 0, "BusyRing"); - qmlRegisterType<QQuickBusyIndicatorAnimator>(import, 2, 0, "BusyRingAnimator"); - qmlRegisterType<QQuickProgressStrip>(import, 2, 0, "ProgressStrip"); - qmlRegisterType<QQuickProgressAnimator>(import, 2, 0, "ProgressStripAnimator"); + qmlRegisterType<QQuickDefaultBusyIndicator>(import, 2, 0, "BusyIndicatorImpl"); + qmlRegisterType<QQuickDefaultProgressBar>(import, 2, 0, "ProgressBarImpl"); qmlRegisterType<QQuickDialRing>(import, 2, 0, "DialRing"); qmlRegisterType<QQuickTumblerView>(import, 2, 1, "TumblerView"); qmlRegisterSingletonType<QQuickDefaultStyle>(import, 2, 1, "Default", styleSingleton); diff --git a/src/imports/controls/universal/BusyIndicator.qml b/src/imports/controls/universal/BusyIndicator.qml index 514a233e..180396f2 100644 --- a/src/imports/controls/universal/BusyIndicator.qml +++ b/src/imports/controls/universal/BusyIndicator.qml @@ -45,9 +45,7 @@ T.BusyIndicator { implicitWidth: contentItem.implicitWidth + leftPadding + rightPadding implicitHeight: contentItem.implicitHeight + topPadding + bottomPadding - contentItem: ProgressRing { - id: ring - + contentItem: BusyIndicatorImpl { implicitWidth: 20 implicitHeight: 20 @@ -55,10 +53,6 @@ T.BusyIndicator { count: size < 60 ? 5 : 6 // "Small" vs. "Large" color: control.Universal.accent - - ProgressRingAnimator { - target: ring - running: control.visible && control.running - } + visible: control.running } } diff --git a/src/imports/controls/universal/Dial.qml b/src/imports/controls/universal/Dial.qml index 9eaf69ba..e473379f 100644 --- a/src/imports/controls/universal/Dial.qml +++ b/src/imports/controls/universal/Dial.qml @@ -35,7 +35,7 @@ ****************************************************************************/ import QtQuick 2.8 -import QtQuick.Templates 2.1 as T +import QtQuick.Templates 2.2 as T import QtQuick.Controls.Universal 2.1 T.Dial { diff --git a/src/imports/controls/universal/ProgressBar.qml b/src/imports/controls/universal/ProgressBar.qml index cd314c27..b85a4581 100644 --- a/src/imports/controls/universal/ProgressBar.qml +++ b/src/imports/controls/universal/ProgressBar.qml @@ -47,20 +47,13 @@ T.ProgressBar { implicitHeight: Math.max(background ? background.implicitHeight : 0, contentItem.implicitHeight + topPadding + bottomPadding) - contentItem: ProgressStrip { - id: strip + contentItem: ProgressBarImpl { implicitHeight: 10 scale: control.mirrored ? -1 : 1 - indeterminate: control.indeterminate color: control.Universal.accent progress: control.position - clip: control.indeterminate - - ProgressStripAnimator { - target: strip - running: control.visible && control.indeterminate - } + indeterminate: control.visible && control.indeterminate } background: Rectangle { diff --git a/src/imports/controls/universal/RangeSlider.qml b/src/imports/controls/universal/RangeSlider.qml index fec8bb18..cfbeb878 100644 --- a/src/imports/controls/universal/RangeSlider.qml +++ b/src/imports/controls/universal/RangeSlider.qml @@ -35,7 +35,7 @@ ****************************************************************************/ import QtQuick 2.8 -import QtQuick.Templates 2.1 as T +import QtQuick.Templates 2.2 as T import QtQuick.Controls.Universal 2.1 T.RangeSlider { diff --git a/src/imports/controls/universal/Slider.qml b/src/imports/controls/universal/Slider.qml index 472f5455..b46f2393 100644 --- a/src/imports/controls/universal/Slider.qml +++ b/src/imports/controls/universal/Slider.qml @@ -35,7 +35,7 @@ ****************************************************************************/ import QtQuick 2.8 -import QtQuick.Templates 2.1 as T +import QtQuick.Templates 2.2 as T import QtQuick.Controls.Universal 2.1 T.Slider { diff --git a/src/imports/controls/universal/Tumbler.qml b/src/imports/controls/universal/Tumbler.qml index e7093d0a..a8033551 100644 --- a/src/imports/controls/universal/Tumbler.qml +++ b/src/imports/controls/universal/Tumbler.qml @@ -35,9 +35,9 @@ ****************************************************************************/ import QtQuick 2.8 -import QtQuick.Templates 2.1 as T +import QtQuick.Templates 2.2 as T import QtQuick.Controls.Universal 2.1 -import QtQuick.Controls 2.1 +import QtQuick.Controls 2.2 import QtQuick.Controls.impl 2.1 T.Tumbler { diff --git a/src/imports/controls/universal/qquickuniversalprogressring.cpp b/src/imports/controls/universal/qquickuniversalbusyindicator.cpp index 1d733fed..acefc5e3 100644 --- a/src/imports/controls/universal/qquickuniversalprogressring.cpp +++ b/src/imports/controls/universal/qquickuniversalbusyindicator.cpp @@ -34,12 +34,12 @@ ** ****************************************************************************/ -#include "qquickuniversalprogressring_p.h" +#include "qquickuniversalbusyindicator_p.h" #include <QtCore/qmath.h> #include <QtCore/qeasingcurve.h> +#include <QtCore/qelapsedtimer.h> #include <QtQuick/private/qquickitem_p.h> -#include <QtQuick/private/qquickanimatorjob_p.h> #include <QtQuick/private/qsgadaptationlayer_p.h> QT_BEGIN_NAMESPACE @@ -48,16 +48,15 @@ static const int PhaseCount = 6; static const int Interval = 167; static const int TotalDuration = 4052; -class QQuickUniversalProgressRingAnimatorJob : public QQuickAnimatorJob +class QQuickUniversalBusyIndicatorNode : public QObject, public QSGTransformNode { public: - QQuickUniversalProgressRingAnimatorJob(); + QQuickUniversalBusyIndicatorNode(QQuickUniversalBusyIndicator *item); - void initialize(QQuickAnimatorController *controller) override; - void updateCurrentTime(int time) override; - void writeBack() override; - void nodeWasDestroyed() override; - void afterNodeSync() override; + int elapsed() const; + + void animate(); + void sync(QQuickUniversalBusyIndicator *item); private: struct Phase { @@ -69,12 +68,18 @@ private: QEasingCurve curve; }; - QSGNode *m_node; + int m_offset; + QElapsedTimer m_timer; Phase m_phases[PhaseCount]; }; -QQuickUniversalProgressRingAnimatorJob::QQuickUniversalProgressRingAnimatorJob() : m_node(nullptr) +QQuickUniversalBusyIndicatorNode::QQuickUniversalBusyIndicatorNode(QQuickUniversalBusyIndicator *item) + : m_offset(item->elapsed()) { + QQuickWindow *window = item->window(); + connect(window, &QQuickWindow::frameSwapped, window, &QQuickWindow::update); + connect(window, &QQuickWindow::beforeRendering, this, &QQuickUniversalBusyIndicatorNode::animate); + m_phases[0] = Phase(433, -110, 10, QEasingCurve::BezierSpline); m_phases[1] = Phase(767, 10, 93, QEasingCurve::Linear ); m_phases[2] = Phase(417, 93, 205, QEasingCurve::BezierSpline); @@ -86,27 +91,26 @@ QQuickUniversalProgressRingAnimatorJob::QQuickUniversalProgressRingAnimatorJob() m_phases[2].curve.addCubicBezierSegment(QPointF(0.57, 0.17), QPointF(0.95, 0.75), QPointF(1.00, 1.00)); m_phases[3].curve.addCubicBezierSegment(QPointF(0.00, 0.19), QPointF(0.07, 0.72), QPointF(1.00, 1.00)); m_phases[5].curve.addCubicBezierSegment(QPointF(0.00, 0.00), QPointF(0.95, 0.37), QPointF(1.00, 1.00)); + + m_timer.restart(); } -void QQuickUniversalProgressRingAnimatorJob::initialize(QQuickAnimatorController *controller) +int QQuickUniversalBusyIndicatorNode::elapsed() const { - QQuickAnimatorJob::initialize(controller); - m_node = QQuickItemPrivate::get(m_target)->childContainerNode(); + return m_timer.elapsed() + m_offset; } -void QQuickUniversalProgressRingAnimatorJob::updateCurrentTime(int time) +void QQuickUniversalBusyIndicatorNode::animate() { - if (!m_node) - return; - - QSGNode *containerNode = m_node->firstChild(); - Q_ASSERT(!containerNode || containerNode->type() == QSGNode::TransformNodeType); - if (!containerNode) - return; + qint64 time = m_timer.elapsed() + m_offset; + if (time >= TotalDuration) { + m_timer.restart(); + m_offset = 0; + } int nodeIndex = 0; - int count = containerNode->childCount(); - QSGTransformNode *transformNode = static_cast<QSGTransformNode *>(containerNode->firstChild()); + int count = childCount(); + QSGTransformNode *transformNode = static_cast<QSGTransformNode *>(firstChild()); while (transformNode) { Q_ASSERT(transformNode->type() == QSGNode::TransformNodeType); @@ -147,126 +151,115 @@ void QQuickUniversalProgressRingAnimatorJob::updateCurrentTime(int time) } } -void QQuickUniversalProgressRingAnimatorJob::writeBack() +void QQuickUniversalBusyIndicatorNode::sync(QQuickUniversalBusyIndicator *item) { -} + QQuickItemPrivate *d = QQuickItemPrivate::get(item); -void QQuickUniversalProgressRingAnimatorJob::nodeWasDestroyed() -{ - m_node = nullptr; -} + QMatrix4x4 matrix; + matrix.translate(item->width() / 2, item->height() / 2); + setMatrix(matrix); -void QQuickUniversalProgressRingAnimatorJob::afterNodeSync() -{ - m_node = QQuickItemPrivate::get(m_target)->childContainerNode(); -} + qreal size = qMin(item->width(), item->height()); + qreal diameter = size / 10.0; + qreal radius = diameter / 2; + qreal offset = (size - diameter * 2) / M_PI; + const QRectF rect(offset, offset, diameter, diameter); -QQuickUniversalProgressRingAnimator::QQuickUniversalProgressRingAnimator(QObject *parent) - : QQuickAnimator(parent) -{ - setDuration(TotalDuration); - setLoops(QQuickAnimator::Infinite); -} + int count = item->count(); + QSGNode *transformNode = firstChild(); + for (int i = 0; i < count; ++i) { + if (!transformNode) { + transformNode = new QSGTransformNode; + appendChildNode(transformNode); -QString QQuickUniversalProgressRingAnimator::propertyName() const -{ - return QString(); -} + QSGOpacityNode *opacityNode = new QSGOpacityNode; + transformNode->appendChildNode(opacityNode); -QQuickAnimatorJob *QQuickUniversalProgressRingAnimator::createJob() const -{ - return new QQuickUniversalProgressRingAnimatorJob; + QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode(); + rectNode->setAntialiasing(true); + opacityNode->appendChildNode(rectNode); + } + + QSGNode *opacityNode = transformNode->firstChild(); + Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType); + + QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild()); + Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType); + + rectNode->setRect(rect); + rectNode->setColor(item->color()); + rectNode->setRadius(radius); + rectNode->update(); + + transformNode = transformNode->nextSibling(); + } + + while (transformNode) { + QSGNode *nextSibling = transformNode->nextSibling(); + delete transformNode; + transformNode = nextSibling; + } } -QQuickUniversalProgressRing::QQuickUniversalProgressRing(QQuickItem *parent) - : QQuickItem(parent), m_count(5), m_color(Qt::black) +QQuickUniversalBusyIndicator::QQuickUniversalBusyIndicator(QQuickItem *parent) + : QQuickItem(parent), m_count(5), m_elapsed(0), m_color(Qt::black) { setFlag(ItemHasContents); } -int QQuickUniversalProgressRing::count() const +int QQuickUniversalBusyIndicator::count() const { return m_count; } -void QQuickUniversalProgressRing::setCount(int count) +void QQuickUniversalBusyIndicator::setCount(int count) { if (m_count == count) return; m_count = count; update(); - emit countChanged(); } -QColor QQuickUniversalProgressRing::color() const +QColor QQuickUniversalBusyIndicator::color() const { return m_color; } -void QQuickUniversalProgressRing::setColor(const QColor &color) +void QQuickUniversalBusyIndicator::setColor(const QColor &color) { if (m_color == color) return; m_color = color; update(); - emit colorChanged(); } -QSGNode *QQuickUniversalProgressRing::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) +int QQuickUniversalBusyIndicator::elapsed() const { - QQuickItemPrivate *d = QQuickItemPrivate::get(this); - - if (!oldNode) - oldNode = new QSGTransformNode; - Q_ASSERT(oldNode->type() == QSGNode::TransformNodeType); - - QMatrix4x4 matrix; - matrix.translate(width() / 2, height() / 2); - static_cast<QSGTransformNode *>(oldNode)->setMatrix(matrix); - - qreal size = qMin(width(), height()); - qreal diameter = size / 10.0; - qreal radius = diameter / 2; - qreal offset = (size - diameter * 2) / M_PI; - const QRectF rect(offset, offset, diameter, diameter); - - QSGNode *transformNode = oldNode->firstChild(); - for (int i = 0; i < m_count; ++i) { - if (!transformNode) { - transformNode = new QSGTransformNode; - oldNode->appendChildNode(transformNode); - - QSGOpacityNode *opacityNode = new QSGOpacityNode; - transformNode->appendChildNode(opacityNode); - - QSGInternalRectangleNode *rectNode = d->sceneGraphContext()->createInternalRectangleNode(); - rectNode->setAntialiasing(true); - opacityNode->appendChildNode(rectNode); - } - - QSGNode *opacityNode = transformNode->firstChild(); - Q_ASSERT(opacityNode->type() == QSGNode::OpacityNodeType); - - QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild()); - Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType); - - rectNode->setRect(rect); - rectNode->setColor(m_color); - rectNode->setRadius(radius); - rectNode->update(); + return m_elapsed; +} - transformNode = transformNode->nextSibling(); - } +void QQuickUniversalBusyIndicator::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) +{ + QQuickItem::itemChange(change, data); + if (change == ItemVisibleHasChanged) + update(); +} - while (transformNode) { - QSGNode *nextSibling = transformNode->nextSibling(); - delete transformNode; - transformNode = nextSibling; +QSGNode *QQuickUniversalBusyIndicator::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) +{ + QQuickUniversalBusyIndicatorNode *node = static_cast<QQuickUniversalBusyIndicatorNode *>(oldNode); + if (isVisible() && width() > 0 && height() > 0) { + if (!node) + node = new QQuickUniversalBusyIndicatorNode(this); + node->sync(this); + } else { + m_elapsed = node ? node->elapsed() : 0; + delete node; + node = nullptr; } - - return oldNode; + return node; } QT_END_NAMESPACE diff --git a/src/imports/controls/universal/qquickuniversalprogressring_p.h b/src/imports/controls/universal/qquickuniversalbusyindicator_p.h index ef73ebed..7e3484d8 100644 --- a/src/imports/controls/universal/qquickuniversalprogressring_p.h +++ b/src/imports/controls/universal/qquickuniversalbusyindicator_p.h @@ -34,8 +34,8 @@ ** ****************************************************************************/ -#ifndef QQUICKUNIVERSALPROGRESSRING_P_H -#define QQUICKUNIVERSALPROGRESSRING_P_H +#ifndef QQUICKUNIVERSALBUSYINDICATOR_P_H +#define QQUICKUNIVERSALBUSYINDICATOR_P_H // // W A R N I N G @@ -49,18 +49,17 @@ // #include <QtQuick/qquickitem.h> -#include <QtQuick/private/qquickanimator_p.h> QT_BEGIN_NAMESPACE -class QQuickUniversalProgressRing : public QQuickItem +class QQuickUniversalBusyIndicator : public QQuickItem { Q_OBJECT - Q_PROPERTY(int count READ count WRITE setCount NOTIFY countChanged FINAL) - Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged FINAL) + Q_PROPERTY(int count READ count WRITE setCount FINAL) + Q_PROPERTY(QColor color READ color WRITE setColor FINAL) public: - QQuickUniversalProgressRing(QQuickItem *parent = nullptr); + explicit QQuickUniversalBusyIndicator(QQuickItem *parent = nullptr); int count() const; void setCount(int count); @@ -68,32 +67,20 @@ public: QColor color() const; void setColor(const QColor &color); -Q_SIGNALS: - void countChanged(); - void colorChanged(); + int elapsed() const; protected: + void itemChange(ItemChange change, const ItemChangeData &data) override; QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override; private: int m_count; + int m_elapsed; QColor m_color; }; -class QQuickUniversalProgressRingAnimator : public QQuickAnimator -{ - Q_OBJECT - -public: - QQuickUniversalProgressRingAnimator(QObject *parent = nullptr); - -protected: - QString propertyName() const override; - QQuickAnimatorJob *createJob() const override; -}; - QT_END_NAMESPACE -QML_DECLARE_TYPE(QQuickUniversalProgressRing) +QML_DECLARE_TYPE(QQuickUniversalBusyIndicator) -#endif // QQUICKUNIVERSALPROGRESSRING_P_H +#endif // QQUICKUNIVERSALBUSYINDICATOR_P_H diff --git a/src/imports/controls/universal/qquickuniversalprogressstrip.cpp b/src/imports/controls/universal/qquickuniversalprogressbar.cpp index 32af5113..5e889f55 100644 --- a/src/imports/controls/universal/qquickuniversalprogressstrip.cpp +++ b/src/imports/controls/universal/qquickuniversalprogressbar.cpp @@ -34,12 +34,12 @@ ** ****************************************************************************/ -#include "qquickuniversalprogressstrip_p.h" +#include "qquickuniversalprogressbar_p.h" #include <QtCore/qmath.h> #include <QtCore/qeasingcurve.h> +#include <QtCore/qelapsedtimer.h> #include <QtQuick/private/qquickitem_p.h> -#include <QtQuick/private/qquickanimatorjob_p.h> #include <QtQuick/private/qsgadaptationlayer_p.h> #include <QtQuick/qsgrectanglenode.h> @@ -57,16 +57,13 @@ static const qreal ContainerAnimationEndPosition = 0.435222; // relative static const qreal EllipseAnimationWellPosition = 0.333333333333333; // relative static const qreal EllipseAnimationEndPosition = 0.666666666666667; // relative -class QQuickUniversalProgressStripAnimatorJob : public QQuickAnimatorJob +class QQuickUniversalProgressBarNode : public QObject, public QSGNode { public: - QQuickUniversalProgressStripAnimatorJob(); + QQuickUniversalProgressBarNode(QQuickUniversalProgressBar *item); - void initialize(QQuickAnimatorController *controller) override; - void updateCurrentTime(int time) override; - void writeBack() override; - void nodeWasDestroyed() override; - void afterNodeSync() override; + void animate(); + void sync(QQuickUniversalProgressBar *item); private: struct Phase { @@ -77,12 +74,14 @@ private: qreal to; }; - QSGNode *m_node; + bool m_indeterminate; + QElapsedTimer m_timer; Phase m_borderPhases[PhaseCount]; Phase m_ellipsePhases[PhaseCount]; }; -QQuickUniversalProgressStripAnimatorJob::QQuickUniversalProgressStripAnimatorJob() : m_node(nullptr) +QQuickUniversalProgressBarNode::QQuickUniversalProgressBarNode(QQuickUniversalProgressBar *) + : m_indeterminate(false) { m_borderPhases[0] = Phase( 500, -50, 0); m_borderPhases[1] = Phase(1500, 0, 0); @@ -93,20 +92,17 @@ QQuickUniversalProgressStripAnimatorJob::QQuickUniversalProgressStripAnimatorJob m_ellipsePhases[1] = Phase(1000, EllipseAnimationWellPosition, EllipseAnimationWellPosition); m_ellipsePhases[2] = Phase(1000, EllipseAnimationWellPosition, EllipseAnimationEndPosition); m_ellipsePhases[3] = Phase(1000, EllipseAnimationWellPosition, EllipseAnimationEndPosition); -} -void QQuickUniversalProgressStripAnimatorJob::initialize(QQuickAnimatorController *controller) -{ - QQuickAnimatorJob::initialize(controller); - m_node = QQuickItemPrivate::get(m_target)->childContainerNode(); + m_timer.start(); } -void QQuickUniversalProgressStripAnimatorJob::updateCurrentTime(int time) +void QQuickUniversalProgressBarNode::animate() { - if (!m_node) - return; + qint64 time = m_timer.elapsed(); + if (time >= TotalDuration) + m_timer.restart(); - QSGRectangleNode *geometryNode = static_cast<QSGRectangleNode *>(m_node->firstChild()); + QSGRectangleNode *geometryNode = static_cast<QSGRectangleNode *>(firstChild()); Q_ASSERT(!geometryNode || geometryNode->type() == QSGNode::GeometryNodeType); if (!geometryNode) return; @@ -197,105 +193,40 @@ void QQuickUniversalProgressStripAnimatorJob::updateCurrentTime(int time) } } -void QQuickUniversalProgressStripAnimatorJob::writeBack() -{ -} - -void QQuickUniversalProgressStripAnimatorJob::nodeWasDestroyed() -{ - m_node = nullptr; -} - -void QQuickUniversalProgressStripAnimatorJob::afterNodeSync() -{ - m_node = QQuickItemPrivate::get(m_target)->childContainerNode(); -} - -QQuickUniversalProgressStripAnimator::QQuickUniversalProgressStripAnimator(QObject *parent) - : QQuickAnimator(parent) -{ - setDuration(TotalDuration); - setLoops(QQuickAnimator::Infinite); -} - -QString QQuickUniversalProgressStripAnimator::propertyName() const +void QQuickUniversalProgressBarNode::sync(QQuickUniversalProgressBar *item) { - return QString(); -} - -QQuickAnimatorJob *QQuickUniversalProgressStripAnimator::createJob() const -{ - return new QQuickUniversalProgressStripAnimatorJob; -} - -QQuickUniversalProgressStrip::QQuickUniversalProgressStrip(QQuickItem *parent) - : QQuickItem(parent), m_color(Qt::black), m_progress(0.0), m_indeterminate(false) -{ - setFlag(ItemHasContents); -} - -QColor QQuickUniversalProgressStrip::color() const -{ - return m_color; -} - -void QQuickUniversalProgressStrip::setColor(const QColor &color) -{ - if (m_color == color) - return; - - m_color = color; - update(); -} - -qreal QQuickUniversalProgressStrip::progress() const -{ - return m_progress; -} - -void QQuickUniversalProgressStrip::setProgress(qreal progress) -{ - if (progress == m_progress) - return; - - m_progress = progress; - update(); -} - -bool QQuickUniversalProgressStrip::isIndeterminate() const -{ - return m_indeterminate; -} - -void QQuickUniversalProgressStrip::setIndeterminate(bool indeterminate) -{ - if (indeterminate == m_indeterminate) - return; - - m_indeterminate = indeterminate; - update(); -} + if (m_indeterminate != item->isIndeterminate()) { + m_indeterminate = item->isIndeterminate(); + QQuickWindow *window = item->window(); + if (m_indeterminate) { + connect(window, &QQuickWindow::frameSwapped, window, &QQuickWindow::update); + connect(window, &QQuickWindow::beforeRendering, this, &QQuickUniversalProgressBarNode::animate); + } else { + disconnect(window, &QQuickWindow::frameSwapped, window, &QQuickWindow::update); + disconnect(window, &QQuickWindow::beforeRendering, this, &QQuickUniversalProgressBarNode::animate); + } + } -QSGNode *QQuickUniversalProgressStrip::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) -{ - QQuickItemPrivate *d = QQuickItemPrivate::get(this); + QQuickItemPrivate *d = QQuickItemPrivate::get(item); - QRectF bounds = boundingRect(); - bounds.setHeight(implicitHeight()); - bounds.moveTop((height() - bounds.height()) / 2.0); + QRectF bounds = item->boundingRect(); + bounds.setHeight(item->implicitHeight()); + bounds.moveTop((item->height() - bounds.height()) / 2.0); if (!m_indeterminate) - bounds.setWidth(m_progress * bounds.width()); + bounds.setWidth(item->progress() * bounds.width()); - QSGRectangleNode *geometryNode = static_cast<QSGRectangleNode *>(oldNode); - if (!geometryNode) - geometryNode = window()->createRectangleNode(); + QSGRectangleNode *geometryNode = static_cast<QSGRectangleNode *>(firstChild()); + if (!geometryNode) { + geometryNode = item->window()->createRectangleNode(); + appendChildNode(geometryNode); + } geometryNode->setRect(bounds); - geometryNode->setColor(m_indeterminate ? Qt::transparent : m_color); + geometryNode->setColor(m_indeterminate ? Qt::transparent : item->color()); if (!m_indeterminate) { while (QSGNode *node = geometryNode->firstChild()) delete node; - return geometryNode; + return; } QSGTransformNode *gridNode = static_cast<QSGTransformNode *>(geometryNode->firstChild()); @@ -333,14 +264,82 @@ QSGNode *QQuickUniversalProgressStrip::updatePaintNode(QSGNode *oldNode, UpdateP QSGInternalRectangleNode *rectNode = static_cast<QSGInternalRectangleNode *>(opacityNode->firstChild()); Q_ASSERT(rectNode->type() == QSGNode::GeometryNodeType); - rectNode->setRect(QRectF((EllipseCount - i - 1) * (EllipseDiameter + EllipseOffset), (height() - EllipseDiameter) / 2, EllipseDiameter, EllipseDiameter)); - rectNode->setColor(m_color); + rectNode->setRect(QRectF((EllipseCount - i - 1) * (EllipseDiameter + EllipseOffset), (item->height() - EllipseDiameter) / 2, EllipseDiameter, EllipseDiameter)); + rectNode->setColor(item->color()); rectNode->update(); borderNode = borderNode->nextSibling(); } +} + +QQuickUniversalProgressBar::QQuickUniversalProgressBar(QQuickItem *parent) + : QQuickItem(parent), m_color(Qt::black), m_progress(0.0), m_indeterminate(false) +{ + setFlag(ItemHasContents); +} + +QColor QQuickUniversalProgressBar::color() const +{ + return m_color; +} + +void QQuickUniversalProgressBar::setColor(const QColor &color) +{ + if (m_color == color) + return; + + m_color = color; + update(); +} + +qreal QQuickUniversalProgressBar::progress() const +{ + return m_progress; +} + +void QQuickUniversalProgressBar::setProgress(qreal progress) +{ + if (progress == m_progress) + return; + + m_progress = progress; + update(); +} + +bool QQuickUniversalProgressBar::isIndeterminate() const +{ + return m_indeterminate; +} + +void QQuickUniversalProgressBar::setIndeterminate(bool indeterminate) +{ + if (indeterminate == m_indeterminate) + return; + + m_indeterminate = indeterminate; + setClip(m_indeterminate); + update(); +} - return geometryNode; +void QQuickUniversalProgressBar::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &data) +{ + QQuickItem::itemChange(change, data); + if (change == ItemVisibleHasChanged) + update(); +} + +QSGNode *QQuickUniversalProgressBar::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNodeData *) +{ + QQuickUniversalProgressBarNode *node = static_cast<QQuickUniversalProgressBarNode *>(oldNode); + if (isVisible() && width() > 0 && height() > 0) { + if (!node) + node = new QQuickUniversalProgressBarNode(this); + node->sync(this); + } else { + delete node; + node = nullptr; + } + return node; } QT_END_NAMESPACE diff --git a/src/imports/controls/universal/qquickuniversalprogressstrip_p.h b/src/imports/controls/universal/qquickuniversalprogressbar_p.h index 89350e4d..04e5ff3c 100644 --- a/src/imports/controls/universal/qquickuniversalprogressstrip_p.h +++ b/src/imports/controls/universal/qquickuniversalprogressbar_p.h @@ -34,8 +34,8 @@ ** ****************************************************************************/ -#ifndef QQUICKUNIVERSALPROGRESSSTRIP_P_H -#define QQUICKUNIVERSALPROGRESSSTRIP_P_H +#ifndef QQUICKUNIVERSALPROGRESSBAR_P_H +#define QQUICKUNIVERSALPROGRESSBAR_P_H // // W A R N I N G @@ -49,11 +49,10 @@ // #include <QtQuick/qquickitem.h> -#include <QtQuick/private/qquickanimator_p.h> QT_BEGIN_NAMESPACE -class QQuickUniversalProgressStrip : public QQuickItem +class QQuickUniversalProgressBar : public QQuickItem { Q_OBJECT Q_PROPERTY(QColor color READ color WRITE setColor FINAL) @@ -61,7 +60,7 @@ class QQuickUniversalProgressStrip : public QQuickItem Q_PROPERTY(bool indeterminate READ isIndeterminate WRITE setIndeterminate FINAL) public: - QQuickUniversalProgressStrip(QQuickItem *parent = nullptr); + explicit QQuickUniversalProgressBar(QQuickItem *parent = nullptr); QColor color() const; void setColor(const QColor &color); @@ -73,6 +72,7 @@ public: void setIndeterminate(bool indeterminate); protected: + void itemChange(ItemChange change, const ItemChangeData &data) override; QSGNode *updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData *) override; private: @@ -81,21 +81,8 @@ private: bool m_indeterminate; }; -class QQuickUniversalProgressStripAnimator : public QQuickAnimator -{ - Q_OBJECT - -public: - QQuickUniversalProgressStripAnimator(QObject *parent = nullptr); - -protected: - QString propertyName() const override; - QQuickAnimatorJob *createJob() const override; -}; - QT_END_NAMESPACE -QML_DECLARE_TYPE(QQuickUniversalProgressStrip) -QML_DECLARE_TYPE(QQuickUniversalProgressStripAnimator) +QML_DECLARE_TYPE(QQuickUniversalProgressBar) -#endif // QQUICKUNIVERSALPROGRESSSTRIP_P_H +#endif // QQUICKUNIVERSALPROGRESSBAR_P_H diff --git a/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp b/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp index 394e9162..be7c8a76 100644 --- a/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp +++ b/src/imports/controls/universal/qtquickcontrols2universalstyleplugin.cpp @@ -36,9 +36,9 @@ #include <QtQuickControls2/private/qquickstyleplugin_p.h> +#include "qquickuniversalbusyindicator_p.h" #include "qquickuniversalfocusrectangle_p.h" -#include "qquickuniversalprogressring_p.h" -#include "qquickuniversalprogressstrip_p.h" +#include "qquickuniversalprogressbar_p.h" #include "qquickuniversalstyle_p.h" #include "qquickuniversaltheme_p.h" @@ -88,11 +88,9 @@ void QtQuickControls2UniversalStylePlugin::initializeEngine(QQmlEngine *engine, QByteArray import = QByteArray(uri) + ".impl"; qmlRegisterType<QQuickUniversalFocusRectangle>(import, 2, 0, "FocusRectangle"); + qmlRegisterType<QQuickUniversalBusyIndicator>(import, 2, 0, "BusyIndicatorImpl"); + qmlRegisterType<QQuickUniversalProgressBar>(import, 2, 0, "ProgressBarImpl"); qmlRegisterRevision<QQuickUniversalFocusRectangle, 1>(import, 2, 1); - qmlRegisterType<QQuickUniversalProgressRing>(import, 2, 0, "ProgressRing"); - qmlRegisterType<QQuickUniversalProgressRingAnimator>(import, 2, 0, "ProgressRingAnimator"); - qmlRegisterType<QQuickUniversalProgressStrip>(import, 2, 0, "ProgressStrip"); - qmlRegisterType<QQuickUniversalProgressStripAnimator>(import, 2, 0, "ProgressStripAnimator"); qmlRegisterType(typeUrl(QStringLiteral("RadioIndicator.qml")), import, 2, 0, "RadioIndicator"); qmlRegisterType(typeUrl(QStringLiteral("SwitchIndicator.qml")), import, 2, 0, "SwitchIndicator"); diff --git a/src/imports/controls/universal/universal.pri b/src/imports/controls/universal/universal.pri index 3697a2a6..833bf2b6 100644 --- a/src/imports/controls/universal/universal.pri +++ b/src/imports/controls/universal/universal.pri @@ -47,15 +47,15 @@ QML_FILES += \ $$PWD/Tumbler.qml HEADERS += \ + $$PWD/qquickuniversalbusyindicator_p.h \ $$PWD/qquickuniversalfocusrectangle_p.h \ - $$PWD/qquickuniversalprogressring_p.h \ - $$PWD/qquickuniversalprogressstrip_p.h \ + $$PWD/qquickuniversalprogressbar_p.h \ $$PWD/qquickuniversalstyle_p.h \ $$PWD/qquickuniversaltheme_p.h SOURCES += \ + $$PWD/qquickuniversalbusyindicator.cpp \ $$PWD/qquickuniversalfocusrectangle.cpp \ - $$PWD/qquickuniversalprogressring.cpp \ - $$PWD/qquickuniversalprogressstrip.cpp \ + $$PWD/qquickuniversalprogressbar.cpp \ $$PWD/qquickuniversalstyle.cpp \ $$PWD/qquickuniversaltheme.cpp diff --git a/src/imports/templates/qtquicktemplates2plugin.cpp b/src/imports/templates/qtquicktemplates2plugin.cpp index cc344a80..88ee9b58 100644 --- a/src/imports/templates/qtquicktemplates2plugin.cpp +++ b/src/imports/templates/qtquicktemplates2plugin.cpp @@ -197,6 +197,12 @@ void QtQuickTemplates2Plugin::registerTypes(const char *uri) qmlRegisterType<QQuickTextField, 1>(uri, 2, 1, "TextField"); qmlRegisterType<QQuickToolSeparator>(uri, 2, 1, "ToolSeparator"); qmlRegisterType<QQuickTumbler, 1>(uri, 2, 1, "Tumbler"); + + // QtQuick.Templates 2.2 (Qt 5.9) + qmlRegisterRevision<QQuickDial, 2>(uri, 2, 2); + qmlRegisterRevision<QQuickRangeSlider, 2>(uri, 2, 2); + qmlRegisterRevision<QQuickSlider, 2>(uri, 2, 2); + qmlRegisterRevision<QQuickTumbler, 2>(uri, 2, 2); } QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickdial.cpp b/src/quicktemplates2/qquickdial.cpp index 48d02faa..eb60c93c 100644 --- a/src/quicktemplates2/qquickdial.cpp +++ b/src/quicktemplates2/qquickdial.cpp @@ -95,6 +95,7 @@ public: pressed(false), snapMode(QQuickDial::NoSnap), wrap(false), + live(false), handle(nullptr) { } @@ -116,6 +117,7 @@ public: QPoint pressPoint; QQuickDial::SnapMode snapMode; bool wrap; + bool live; QQuickItem *handle; }; @@ -246,11 +248,12 @@ void QQuickDial::setTo(qreal to) This property holds the value in the range \c from - \c to. The default value is \c 0.0. - Unlike the \l position property, the \c value is not updated while the - handle is dragged. The value is updated after the value has been chosen - and the dial has been released. + Unlike the \l position property, the \c value is not updated by default + while the handle is dragged. The value is updated after the value has + been chosen and the dial has been released. The \l live property can be + used to make the dial provide live updates for the \c value property. - \sa position + \sa position, live */ qreal QQuickDial::value() const { @@ -445,6 +448,33 @@ void QQuickDial::setPressed(bool pressed) } /*! + \since QtQuick.Controls 2.2 + \qmlproperty bool QtQuick.Controls::Dial::live + + This property holds whether the dial provides live updates for the \l value + property while the handle is dragged. + + The default value is \c false. + + \sa value +*/ +bool QQuickDial::live() const +{ + Q_D(const QQuickDial); + return d->live; +} + +void QQuickDial::setLive(bool live) +{ + Q_D(QQuickDial); + if (d->live == live) + return; + + d->live = live; + emit liveChanged(); +} + +/*! \qmlmethod void QtQuick.Controls::Dial::increase() Increases the value by \l stepSize, or \c 0.1 if stepSize is not defined. @@ -571,8 +601,12 @@ void QQuickDial::mouseMoveEvent(QMouseEvent *event) if (d->snapMode == SnapAlways) pos = d->snapPosition(pos); - if (d->wrap || (!d->wrap && !d->isLargeChange(event->pos(), pos))) - d->setPosition(pos); + if (d->wrap || (!d->wrap && !d->isLargeChange(event->pos(), pos))) { + if (d->live) + setValue(d->valueAt(pos)); + else + d->setPosition(pos); + } } } diff --git a/src/quicktemplates2/qquickdial_p.h b/src/quicktemplates2/qquickdial_p.h index 2d87d6d9..17a44b7a 100644 --- a/src/quicktemplates2/qquickdial_p.h +++ b/src/quicktemplates2/qquickdial_p.h @@ -69,6 +69,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickDial : public QQuickControl Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged FINAL) Q_PROPERTY(bool wrap READ wrap WRITE setWrap NOTIFY wrapChanged FINAL) Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged FINAL) + Q_PROPERTY(bool live READ live WRITE setLive NOTIFY liveChanged FINAL REVISION 2) Q_PROPERTY(QQuickItem *handle READ handle WRITE setHandle NOTIFY handleChanged FINAL) public: @@ -106,6 +107,9 @@ public: bool isPressed() const; void setPressed(bool pressed); + bool live() const; + void setLive(bool live); + QQuickItem *handle() const; void setHandle(QQuickItem *handle); @@ -123,6 +127,7 @@ Q_SIGNALS: void snapModeChanged(); void wrapChanged(); void pressedChanged(); + Q_REVISION(2) void liveChanged(); void handleChanged(); protected: diff --git a/src/quicktemplates2/qquickrangeslider.cpp b/src/quicktemplates2/qquickrangeslider.cpp index 3caf5042..83f34b5b 100644 --- a/src/quicktemplates2/qquickrangeslider.cpp +++ b/src/quicktemplates2/qquickrangeslider.cpp @@ -316,6 +316,7 @@ class QQuickRangeSliderPrivate : public QQuickControlPrivate public: QQuickRangeSliderPrivate() : + live(false), from(defaultFrom), to(defaultTo), stepSize(0), @@ -328,6 +329,7 @@ public: void updateHover(const QPointF &pos); + bool live; qreal from; qreal to; qreal stepSize; @@ -474,8 +476,10 @@ void QQuickRangeSlider::setTo(qreal to) If \l to is greater than \l from, the value of the first handle must be greater than the second, and vice versa. - Unlike \l {first.position}{position}, value is not updated while the - handle is dragged, but rather when it has been released. + Unlike \l {first.position}{position}, value is not updated by default + while the handle is dragged, but rather when it has been released. The + \l live property can be used to make the slider provide live updates + for value. The default value is \c 0.0. \row @@ -536,8 +540,10 @@ QQuickRangeSliderNode *QQuickRangeSlider::first() const If \l to is greater than \l from, the value of the first handle must be greater than the second, and vice versa. - Unlike \l {second.position}{position}, value is not updated while the - handle is dragged, but rather when it has been released. + Unlike \l {second.position}{position}, value is not updated by default + while the handle is dragged, but rather when it has been released. The + \l live property can be used to make the slider provide live updates + for value. The default value is \c 0.0. \row @@ -657,6 +663,33 @@ void QQuickRangeSlider::setOrientation(Qt::Orientation orientation) } /*! + \since QtQuick.Controls 2.2 + \qmlproperty bool QtQuick.Controls::RangeSlider::live + + This property holds whether the slider provides live updates for the \l first.value + and \l second.value properties while the respective handles are dragged. + + The default value is \c false. + + \sa first.value, second.value +*/ +bool QQuickRangeSlider::live() const +{ + Q_D(const QQuickRangeSlider); + return d->live; +} + +void QQuickRangeSlider::setLive(bool live) +{ + Q_D(QQuickRangeSlider); + if (d->live == live) + return; + + d->live = live; + emit liveChanged(); +} + +/*! \qmlmethod void QtQuick.Controls::RangeSlider::setValues(real firstValue, real secondValue) Sets \l first.value and \l second.value with the given arguments. @@ -874,7 +907,10 @@ void QQuickRangeSlider::mouseMoveEvent(QMouseEvent *event) qreal pos = positionAt(this, pressedNode->handle(), event->pos()); if (d->snapMode == SnapAlways) pos = snapPosition(this, pos); - QQuickRangeSliderNodePrivate::get(pressedNode)->setPosition(pos); + if (d->live) + pressedNode->setValue(valueAt(this, pos)); + else + QQuickRangeSliderNodePrivate::get(pressedNode)->setPosition(pos); } } } diff --git a/src/quicktemplates2/qquickrangeslider_p.h b/src/quicktemplates2/qquickrangeslider_p.h index 1b102e87..08e68b0e 100644 --- a/src/quicktemplates2/qquickrangeslider_p.h +++ b/src/quicktemplates2/qquickrangeslider_p.h @@ -65,6 +65,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickRangeSlider : public QQuickControl Q_PROPERTY(qreal stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged FINAL) Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged FINAL) Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL) + Q_PROPERTY(bool live READ live WRITE setLive NOTIFY liveChanged FINAL REVISION 2) public: explicit QQuickRangeSlider(QQuickItem *parent = nullptr); @@ -94,6 +95,9 @@ public: Qt::Orientation orientation() const; void setOrientation(Qt::Orientation orientation); + bool live() const; + void setLive(bool live); + Q_INVOKABLE void setValues(qreal firstValue, qreal secondValue); Q_SIGNALS: @@ -102,6 +106,7 @@ Q_SIGNALS: void stepSizeChanged(); void snapModeChanged(); void orientationChanged(); + Q_REVISION(2) void liveChanged(); protected: void focusInEvent(QFocusEvent *event) override; diff --git a/src/quicktemplates2/qquickslider.cpp b/src/quicktemplates2/qquickslider.cpp index 63fc50ac..f587460f 100644 --- a/src/quicktemplates2/qquickslider.cpp +++ b/src/quicktemplates2/qquickslider.cpp @@ -80,7 +80,7 @@ class QQuickSliderPrivate : public QQuickControlPrivate Q_DECLARE_PUBLIC(QQuickSlider) public: - QQuickSliderPrivate() : from(0), to(1), value(0), position(0), stepSize(0), pressed(false), + QQuickSliderPrivate() : from(0), to(1), value(0), position(0), stepSize(0), live(false), pressed(false), orientation(Qt::Horizontal), snapMode(QQuickSlider::NoSnap), handle(nullptr) { @@ -96,6 +96,7 @@ public: qreal value; qreal position; qreal stepSize; + bool live; bool pressed; QPoint pressPoint; Qt::Orientation orientation; @@ -225,12 +226,12 @@ void QQuickSlider::setTo(qreal to) This property holds the value in the range \c from - \c to. The default value is \c 0.0. - Unlike the \l position property, the \c value is not updated while the - handle is dragged, but only after the value has been chosen and the slider - has been released. The \l valueAt() method can be used to get continuous - updates. + Unlike the \l position property, the \c value is not updated by default + while the handle is dragged, but only after the value has been chosen and + the slider has been released. The \l live property can be used to make the + slider provide live updates for the \c value property. - \sa position, valueAt() + \sa position, live, valueAt() */ qreal QQuickSlider::value() const { @@ -259,9 +260,9 @@ void QQuickSlider::setValue(qreal value) This property holds the logical position of the handle. The position is defined as a percentage of the control's size, scaled - to \c {0.0 - 1.0}. Unlike the \l value property, the \c position is - continuously updated while the handle is dragged. For visualizing a - slider, the right-to-left aware \l visualPosition should be used instead. + to \c {0.0 - 1.0}. The \c position is continuously updated while the + handle is dragged. For visualizing a slider, the right-to-left aware + \l visualPosition should be used instead. \sa value, visualPosition, valueAt() */ @@ -356,6 +357,33 @@ void QQuickSlider::setSnapMode(SnapMode mode) } /*! + \since QtQuick.Controls 2.2 + \qmlproperty bool QtQuick.Controls::Slider::live + + This property holds whether the slider provides live updates for the \l value + property while the handle is dragged. + + The default value is \c false. + + \sa value +*/ +bool QQuickSlider::live() const +{ + Q_D(const QQuickSlider); + return d->live; +} + +void QQuickSlider::setLive(bool live) +{ + Q_D(QQuickSlider); + if (d->live == live) + return; + + d->live = live; + emit liveChanged(); +} + +/*! \qmlproperty bool QtQuick.Controls::Slider::pressed This property holds whether the slider is pressed. @@ -536,7 +564,10 @@ void QQuickSlider::mouseMoveEvent(QMouseEvent *event) qreal pos = d->positionAt(event->pos()); if (d->snapMode == SnapAlways) pos = d->snapPosition(pos); - d->setPosition(pos); + if (d->live) + setValue(valueAt(pos)); + else + d->setPosition(pos); } } diff --git a/src/quicktemplates2/qquickslider_p.h b/src/quicktemplates2/qquickslider_p.h index d17af5c4..7ddffc7e 100644 --- a/src/quicktemplates2/qquickslider_p.h +++ b/src/quicktemplates2/qquickslider_p.h @@ -64,6 +64,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSlider : public QQuickControl Q_PROPERTY(qreal visualPosition READ visualPosition NOTIFY visualPositionChanged FINAL) Q_PROPERTY(qreal stepSize READ stepSize WRITE setStepSize NOTIFY stepSizeChanged FINAL) Q_PROPERTY(SnapMode snapMode READ snapMode WRITE setSnapMode NOTIFY snapModeChanged FINAL) + Q_PROPERTY(bool live READ live WRITE setLive NOTIFY liveChanged FINAL REVISION 2) Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL) Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL) Q_PROPERTY(QQuickItem *handle READ handle WRITE setHandle NOTIFY handleChanged FINAL) @@ -96,6 +97,9 @@ public: SnapMode snapMode() const; void setSnapMode(SnapMode mode); + bool live() const; + void setLive(bool live); + bool isPressed() const; void setPressed(bool pressed); @@ -119,6 +123,7 @@ Q_SIGNALS: void visualPositionChanged(); void stepSizeChanged(); void snapModeChanged(); + Q_REVISION(2) void liveChanged(); void pressedChanged(); void orientationChanged(); void handleChanged(); diff --git a/src/quicktemplates2/qquicktumbler.cpp b/src/quicktemplates2/qquicktumbler.cpp index 49a9c087..068720bb 100644 --- a/src/quicktemplates2/qquicktumbler.cpp +++ b/src/quicktemplates2/qquicktumbler.cpp @@ -439,6 +439,19 @@ void QQuickTumbler::resetWrap() d->setWrapBasedOnCount(); } +/*! + \qmlproperty bool QtQuick.Controls::Tumbler::moving + \since QtQuick.Controls 2.2 + + This property describes whether the tumbler is currently moving, due to + the user either dragging or flicking it. +*/ +bool QQuickTumbler::isMoving() const +{ + Q_D(const QQuickTumbler); + return d->view && d->view->property("moving").toBool(); +} + QQuickTumblerAttached *QQuickTumbler::qmlAttachedProperties(QObject *object) { return new QQuickTumblerAttached(object); @@ -505,6 +518,7 @@ void QQuickTumblerPrivate::disconnectFromView() QObject::disconnect(view, SIGNAL(currentIndexChanged()), q, SLOT(_q_onViewCurrentIndexChanged())); QObject::disconnect(view, SIGNAL(currentItemChanged()), q, SIGNAL(currentItemChanged())); QObject::disconnect(view, SIGNAL(countChanged()), q, SLOT(_q_onViewCountChanged())); + QObject::disconnect(view, SIGNAL(movingChanged()), q, SIGNAL(movingChanged())); QQuickItemPrivate *oldViewContentItemPrivate = QQuickItemPrivate::get(viewContentItem); oldViewContentItemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Children); @@ -529,6 +543,7 @@ void QQuickTumblerPrivate::setupViewData(QQuickItem *newControlContentItem) QObject::connect(view, SIGNAL(currentIndexChanged()), q, SLOT(_q_onViewCurrentIndexChanged())); QObject::connect(view, SIGNAL(currentItemChanged()), q, SIGNAL(currentItemChanged())); QObject::connect(view, SIGNAL(countChanged()), q, SLOT(_q_onViewCountChanged())); + QObject::connect(view, SIGNAL(movingChanged()), q, SIGNAL(movingChanged())); QQuickItemPrivate *viewContentItemPrivate = QQuickItemPrivate::get(viewContentItem); viewContentItemPrivate->addItemChangeListener(this, QQuickItemPrivate::Children); diff --git a/src/quicktemplates2/qquicktumbler_p.h b/src/quicktemplates2/qquicktumbler_p.h index 1c8cfa18..3ec4044c 100644 --- a/src/quicktemplates2/qquicktumbler_p.h +++ b/src/quicktemplates2/qquicktumbler_p.h @@ -67,6 +67,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTumbler : public QQuickControl Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL) Q_PROPERTY(int visibleItemCount READ visibleItemCount WRITE setVisibleItemCount NOTIFY visibleItemCountChanged FINAL) Q_PROPERTY(bool wrap READ wrap WRITE setWrap RESET resetWrap NOTIFY wrapChanged FINAL REVISION 1) + Q_PROPERTY(bool moving READ isMoving NOTIFY movingChanged FINAL REVISION 2) public: explicit QQuickTumbler(QQuickItem *parent = nullptr); @@ -91,6 +92,8 @@ public: void setWrap(bool wrap); void resetWrap(); + bool isMoving() const; + static QQuickTumblerAttached *qmlAttachedProperties(QObject *object); Q_SIGNALS: @@ -101,6 +104,7 @@ Q_SIGNALS: void delegateChanged(); void visibleItemCountChanged(); Q_REVISION(1) void wrapChanged(); + Q_REVISION(2) void movingChanged(); protected: void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; diff --git a/tests/auto/controls/data/tst_dial.qml b/tests/auto/controls/data/tst_dial.qml index e6446d3e..6dd65593 100644 --- a/tests/auto/controls/data/tst_dial.qml +++ b/tests/auto/controls/data/tst_dial.qml @@ -172,9 +172,10 @@ TestCase { function test_dragging_data() { return [ - { tag: "default", from: 0, to: 1, leftValue: 0.20, topValue: 0.5, rightValue: 0.8, bottomValue: 1.0 }, - { tag: "scaled2", from: 0, to: 2, leftValue: 0.4, topValue: 1.0, rightValue: 1.6, bottomValue: 2.0 }, - { tag: "scaled1", from: -1, to: 0, leftValue: -0.8, topValue: -0.5, rightValue: -0.2, bottomValue: 0.0 } + { tag: "default", from: 0, to: 1, leftValue: 0.20, topValue: 0.5, rightValue: 0.8, bottomValue: 1.0, live: false }, + { tag: "scaled2", from: 0, to: 2, leftValue: 0.4, topValue: 1.0, rightValue: 1.6, bottomValue: 2.0, live: false }, + { tag: "scaled1", from: -1, to: 0, leftValue: -0.8, topValue: -0.5, rightValue: -0.2, bottomValue: 0.0, live: false }, + { tag: "live", from: 0, to: 1, leftValue: 0.20, topValue: 0.5, rightValue: 0.8, bottomValue: 1.0, live: true } ] } @@ -183,32 +184,35 @@ TestCase { verify(dial.wrap); dial.from = data.from; dial.to = data.to; + dial.live = data.live; valueSpy.target = dial; verify(valueSpy.valid); + var minimumExpectedValueCount = data.live ? 2 : 1; + // drag to the left mouseDrag(dial, dial.width / 2, dial.height / 2, -dial.width / 2, 0, Qt.LeftButton); fuzzyCompare(dial.value, data.leftValue, 0.1); - verify(valueSpy.count > 0); + verify(valueSpy.count >= minimumExpectedValueCount); valueSpy.clear(); // drag to the top mouseDrag(dial, dial.width / 2, dial.height / 2, 0, -dial.height / 2, Qt.LeftButton); fuzzyCompare(dial.value, data.topValue, 0.1); - verify(valueSpy.count > 0); + verify(valueSpy.count >= minimumExpectedValueCount); valueSpy.clear(); // drag to the right mouseDrag(dial, dial.width / 2, dial.height / 2, dial.width / 2, 0, Qt.LeftButton); fuzzyCompare(dial.value, data.rightValue, 0.1); - verify(valueSpy.count > 0); + verify(valueSpy.count >= minimumExpectedValueCount); valueSpy.clear(); // drag to the bottom (* 0.6 to ensure we don't go over to the minimum position) mouseDrag(dial, dial.width / 2, dial.height / 2, 10, dial.height / 2, Qt.LeftButton); fuzzyCompare(dial.value, data.bottomValue, 0.1); - verify(valueSpy.count > 0); + verify(valueSpy.count >= minimumExpectedValueCount); valueSpy.clear(); } diff --git a/tests/auto/controls/data/tst_rangeslider.qml b/tests/auto/controls/data/tst_rangeslider.qml index eb654bbc..42155dc0 100644 --- a/tests/auto/controls/data/tst_rangeslider.qml +++ b/tests/auto/controls/data/tst_rangeslider.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.1 +import QtQuick.Controls 2.2 TestCase { id: testCase @@ -274,13 +274,15 @@ TestCase { function test_mouse_data() { return [ - { tag: "horizontal", orientation: Qt.Horizontal }, - { tag: "vertical", orientation: Qt.Vertical } + { tag: "horizontal", orientation: Qt.Horizontal, live: false }, + { tag: "vertical", orientation: Qt.Vertical, live: false }, + { tag: "horizontal:live", orientation: Qt.Horizontal, live: true }, + { tag: "vertical:live", orientation: Qt.Vertical, live: true } ] } function test_mouse(data) { - var control = sliderComponent.createObject(testCase, { orientation: data.orientation }) + var control = sliderComponent.createObject(testCase, { orientation: data.orientation, live: data.live }) verify(control) var firstPressedSpy = signalSpy.createObject(control, {target: control.first, signalName: "pressedChanged"}) @@ -366,7 +368,7 @@ TestCase { compare(firstPressedSpy.count, 5) compare(secondPressedSpy.count, 2) compare(control.first.pressed, true) - compare(control.first.value, 0.0) + compare(control.first.value, data.live ? 0.5 : 0.0) compare(control.first.position, 0.5) compare(control.first.visualPosition, 0.5) compare(control.second.pressed, false) diff --git a/tests/auto/controls/data/tst_slider.qml b/tests/auto/controls/data/tst_slider.qml index 029aff14..c5884273 100644 --- a/tests/auto/controls/data/tst_slider.qml +++ b/tests/auto/controls/data/tst_slider.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.1 +import QtQuick.Controls 2.2 TestCase { id: testCase @@ -213,13 +213,15 @@ TestCase { function test_mouse_data() { return [ - { tag: "horizontal", orientation: Qt.Horizontal }, - { tag: "vertical", orientation: Qt.Vertical } + { tag: "horizontal", orientation: Qt.Horizontal, live: false }, + { tag: "vertical", orientation: Qt.Vertical, live: false }, + { tag: "horizontal:live", orientation: Qt.Horizontal, live: true }, + { tag: "vertical:live", orientation: Qt.Vertical, live: true } ] } function test_mouse(data) { - var control = slider.createObject(testCase, {orientation: data.orientation}) + var control = slider.createObject(testCase, {orientation: data.orientation, live: data.live}) verify(control) var pressedSpy = signalSpy.createObject(control, {target: control, signalName: "pressedChanged"}) @@ -241,8 +243,8 @@ TestCase { mouseMove(control, control.width * 0.5, control.height * 0.5, 0, Qt.LeftButton) compare(pressedSpy.count, 1) compare(control.pressed, true) - compare(control.value, 0.0) - verify(control.position, 0.5) + compare(control.value, data.live ? 0.5 : 0.0) + compare(control.position, 0.5) mouseRelease(control, control.width * 0.5, control.height * 0.5, Qt.LeftButton) compare(pressedSpy.count, 2) @@ -260,13 +262,13 @@ TestCase { mouseMove(control, control.width * 2, -control.height, 0, Qt.LeftButton) compare(pressedSpy.count, 3) compare(control.pressed, true) - compare(control.value, 0.5) + compare(control.value, data.live ? 1.0 : 0.5) compare(control.position, 1.0) mouseMove(control, control.width * 0.75, control.height * 0.25, 0, Qt.LeftButton) compare(pressedSpy.count, 3) compare(control.pressed, true) - compare(control.value, 0.5) + compare(control.value, data.live ? control.position : 0.5) verify(control.position >= 0.75) mouseRelease(control, control.width * 0.25, control.height * 0.75, Qt.LeftButton) diff --git a/tests/auto/controls/data/tst_tumbler.qml b/tests/auto/controls/data/tst_tumbler.qml index b3230ca4..bca2e976 100644 --- a/tests/auto/controls/data/tst_tumbler.qml +++ b/tests/auto/controls/data/tst_tumbler.qml @@ -40,7 +40,7 @@ import QtQuick 2.2 import QtTest 1.0 -import QtQuick.Controls 2.1 +import QtQuick.Controls 2.2 TestCase { id: testCase @@ -1045,4 +1045,30 @@ TestCase { ++tumbler.currentIndex; tryCompare(tumblerView, "offset", 4, tumblerView.highlightMoveDuration * 2); } + + function test_moving_data() { + return [ + { tag: "wrap:true", wrap: true }, + { tag: "wrap:false", wrap: false } + ] + } + + function test_moving(data) { + createTumbler({wrap: data.wrap, model: 5}) + compare(tumbler.wrap, data.wrap) + compare(tumbler.moving, false) + + waitForRendering(tumbler) + + mousePress(tumbler, tumbler.width / 2, tumbler.height / 2, Qt.LeftButton) + compare(tumbler.moving, false) + + for (var y = tumbler.height / 2; y >= tumbler.height / 4; y -= 10) + mouseMove(tumbler, tumbler.width / 2, y, 1) + compare(tumbler.moving, true) + + mouseRelease(tumbler, tumbler.width / 2, tumbler.height / 4, Qt.LeftButton) + compare(tumbler.moving, true) + tryCompare(tumbler, "moving", false) + } } |