diff options
author | J-P Nurmi <jpnurmi@qt.io> | 2017-11-03 16:42:14 +0100 |
---|---|---|
committer | J-P Nurmi <jpnurmi@qt.io> | 2017-11-08 10:13:49 +0000 |
commit | f246314b21604c5fe2a2abe0aec8af89f06eb610 (patch) | |
tree | b66ed350b4a1ba96b0b1c90bc64f923b1ae74e66 | |
parent | 501d45012f746d843e0144c78202297a577758bc (diff) |
ScrollIndicator: allow configuring the minimum size
Same as 9e1b044 for ScrollBar.
The existing size and position properties cannot be changed,
because then they won't match with Flickable::visibleArea and
we get major problems connecting the two. Thus, the effective
visible position and size are provided as separate properties.
[ChangeLog][Controls][ScrollIndicator] Added minimumSize, visualSize,
and visualPosition properties.
Task-number: QTBUG-56557
Change-Id: I7deda3bea7a5a020bda79af433bfa38f326952d8
Reviewed-by: Liang Qi <liang.qi@qt.io>
-rw-r--r-- | src/imports/templates/qtquicktemplates2plugin.cpp | 1 | ||||
-rw-r--r-- | src/quicktemplates2/qquickscrollindicator.cpp | 111 | ||||
-rw-r--r-- | src/quicktemplates2/qquickscrollindicator_p.h | 15 | ||||
-rw-r--r-- | tests/auto/controls/data/tst_scrollindicator.qml | 48 |
4 files changed, 168 insertions, 7 deletions
diff --git a/src/imports/templates/qtquicktemplates2plugin.cpp b/src/imports/templates/qtquicktemplates2plugin.cpp index f5d1118f..3564f957 100644 --- a/src/imports/templates/qtquicktemplates2plugin.cpp +++ b/src/imports/templates/qtquicktemplates2plugin.cpp @@ -324,6 +324,7 @@ void QtQuickTemplates2Plugin::registerTypes(const char *uri) qmlRegisterType<QQuickButtonGroup, 4>(uri, 2, 4, "ButtonGroup"); qmlRegisterType<QQuickCheckBox, 4>(uri, 2, 4, "CheckBox"); qmlRegisterType<QQuickScrollBar, 4>(uri, 2, 4, "ScrollBar"); + qmlRegisterType<QQuickScrollIndicator, 4>(uri, 2, 4, "ScrollIndicator"); qmlRegisterType<QQuickSpinBox, 4>(uri, 2, 4, "SpinBox"); } diff --git a/src/quicktemplates2/qquickscrollindicator.cpp b/src/quicktemplates2/qquickscrollindicator.cpp index ee1078e4..511a8311 100644 --- a/src/quicktemplates2/qquickscrollindicator.cpp +++ b/src/quicktemplates2/qquickscrollindicator.cpp @@ -137,20 +137,54 @@ class QQuickScrollIndicatorPrivate : public QQuickControlPrivate public: QQuickScrollIndicatorPrivate() : size(0), + minimumSize(0), position(0), active(false), orientation(Qt::Vertical) { } + struct VisualArea + { + VisualArea(qreal pos, qreal sz) + : position(pos), size(sz) { } + qreal position; + qreal size; + }; + VisualArea visualArea() const; + void visualAreaChange(const VisualArea &newVisualArea, const VisualArea &oldVisualArea); + void resizeContent() override; qreal size; + qreal minimumSize; qreal position; bool active; Qt::Orientation orientation; }; +QQuickScrollIndicatorPrivate::VisualArea QQuickScrollIndicatorPrivate::visualArea() const +{ + qreal visualPos = position; + if (minimumSize > size) + visualPos = position / (1.0 - size) * (1.0 - minimumSize); + + qreal visualSize = qBound<qreal>(0, qMax(size, minimumSize) + qMin<qreal>(0, visualPos), 1.0 - visualPos); + + visualPos = qBound<qreal>(0, visualPos, 1.0 - visualSize); + + return VisualArea(visualPos, visualSize); +} + +void QQuickScrollIndicatorPrivate::visualAreaChange(const VisualArea &newVisualArea, const VisualArea &oldVisualArea) +{ + Q_Q(QQuickScrollIndicator); + if (!qFuzzyCompare(newVisualArea.size, oldVisualArea.size)) + emit q->visualSizeChanged(); + if (!qFuzzyCompare(newVisualArea.position, oldVisualArea.position)) + emit q->visualPositionChanged(); +} + void QQuickScrollIndicatorPrivate::resizeContent() { Q_Q(QQuickScrollIndicator); @@ -159,15 +193,14 @@ void QQuickScrollIndicatorPrivate::resizeContent() // - negative overshoot (pos < 0): clamp the pos to 0, and deduct the overshoot from the size // - positive overshoot (pos + size > 1): clamp the size to 1-pos - const qreal clampedSize = qBound<qreal>(0, size + qMin<qreal>(0, position), 1.0 - position); - const qreal clampedPos = qBound<qreal>(0, position, 1.0 - clampedSize); + const VisualArea visual = visualArea(); if (orientation == Qt::Horizontal) { - contentItem->setPosition(QPointF(q->leftPadding() + clampedPos * q->availableWidth(), q->topPadding())); - contentItem->setSize(QSizeF(q->availableWidth() * clampedSize, q->availableHeight())); + contentItem->setPosition(QPointF(q->leftPadding() + visual.position * q->availableWidth(), q->topPadding())); + contentItem->setSize(QSizeF(q->availableWidth() * visual.size, q->availableHeight())); } else { - contentItem->setPosition(QPointF(q->leftPadding(), q->topPadding() + clampedPos * q->availableHeight())); - contentItem->setSize(QSizeF(q->availableWidth(), q->availableHeight() * clampedSize)); + contentItem->setPosition(QPointF(q->leftPadding(), q->topPadding() + visual.position * q->availableHeight())); + contentItem->setSize(QSizeF(q->availableWidth(), q->availableHeight() * visual.size)); } } @@ -190,6 +223,8 @@ QQuickScrollIndicatorAttached *QQuickScrollIndicator::qmlAttachedProperties(QObj This property is automatically set when the scroll indicator is \l {Attaching ScrollIndicator to a Flickable}{attached to a flickable}. + + \sa minimumSize, visualSize */ qreal QQuickScrollIndicator::size() const { @@ -203,10 +238,12 @@ void QQuickScrollIndicator::setSize(qreal size) if (qFuzzyCompare(d->size, size)) return; + auto oldVisualArea = d->visualArea(); d->size = size; if (isComponentComplete()) d->resizeContent(); emit sizeChanged(); + d->visualAreaChange(d->visualArea(), oldVisualArea); } /*! @@ -217,7 +254,7 @@ void QQuickScrollIndicator::setSize(qreal size) This property is automatically set when the scroll indicator is \l {Attaching ScrollIndicator to a Flickable}{attached to a flickable}. - \sa {Flickable::visibleArea.yPosition}{Flickable::visibleArea} + \sa {Flickable::visibleArea.yPosition}{Flickable::visibleArea}, visualPosition */ qreal QQuickScrollIndicator::position() const { @@ -231,10 +268,12 @@ void QQuickScrollIndicator::setPosition(qreal position) if (qFuzzyCompare(d->position, position)) return; + auto oldVisualArea = d->visualArea(); d->position = position; if (isComponentComplete()) d->resizeContent(); emit positionChanged(); + d->visualAreaChange(d->visualArea(), oldVisualArea); } /*! @@ -327,6 +366,64 @@ bool QQuickScrollIndicator::isVertical() const return d->orientation == Qt::Vertical; } +/*! + \since QtQuick.Controls 2.4 (Qt 5.11) + \qmlproperty real QtQuick.Controls::ScrollIndicator::minimumSize + + This property holds the minimum size of the indicator, scaled to \c {0.0 - 1.0}. + + \sa size, visualSize, visualPosition +*/ +qreal QQuickScrollIndicator::minimumSize() const +{ + Q_D(const QQuickScrollIndicator); + return d->minimumSize; +} + +void QQuickScrollIndicator::setMinimumSize(qreal minimumSize) +{ + Q_D(QQuickScrollIndicator); + if (qFuzzyCompare(d->minimumSize, minimumSize)) + return; + + auto oldVisualArea = d->visualArea(); + d->minimumSize = minimumSize; + if (isComponentComplete()) + d->resizeContent(); + emit minimumSizeChanged(); + d->visualAreaChange(d->visualArea(), oldVisualArea); +} + +/*! + \since QtQuick.Controls 2.4 (Qt 5.11) + \qmlproperty real QtQuick.Controls::ScrollIndicator::visualSize + + This property holds the effective visual size of the indicator, + which may be limited by the \l {minimumSize}{minimum size}. + + \sa size, minimumSize +*/ +qreal QQuickScrollIndicator::visualSize() const +{ + Q_D(const QQuickScrollIndicator); + return d->visualArea().size; +} + +/*! + \since QtQuick.Controls 2.4 (Qt 5.11) + \qmlproperty real QtQuick.Controls::ScrollIndicator::visualPosition + + This property holds the effective visual position of the indicator, + which may be limited by the \l {minimumSize}{minimum size}. + + \sa position, minimumSize +*/ +qreal QQuickScrollIndicator::visualPosition() const +{ + Q_D(const QQuickScrollIndicator); + return d->visualArea().position; +} + class QQuickScrollIndicatorAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener { public: diff --git a/src/quicktemplates2/qquickscrollindicator_p.h b/src/quicktemplates2/qquickscrollindicator_p.h index d679cf74..4fa06a33 100644 --- a/src/quicktemplates2/qquickscrollindicator_p.h +++ b/src/quicktemplates2/qquickscrollindicator_p.h @@ -66,6 +66,10 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickScrollIndicator : public QQuickCont // 2.3 (Qt 5.10) Q_PROPERTY(bool horizontal READ isHorizontal NOTIFY orientationChanged FINAL REVISION 3) Q_PROPERTY(bool vertical READ isVertical NOTIFY orientationChanged FINAL REVISION 3) + // 2.4 (Qt 5.11) + Q_PROPERTY(qreal minimumSize READ minimumSize WRITE setMinimumSize NOTIFY minimumSizeChanged FINAL REVISION 4) + Q_PROPERTY(qreal visualSize READ visualSize NOTIFY visualSizeChanged FINAL REVISION 4) + Q_PROPERTY(qreal visualPosition READ visualPosition NOTIFY visualPositionChanged FINAL REVISION 4) public: explicit QQuickScrollIndicator(QQuickItem *parent = nullptr); @@ -85,6 +89,13 @@ public: bool isHorizontal() const; bool isVertical() const; + // 2.4 (Qt 5.11) + qreal minimumSize() const; + void setMinimumSize(qreal minimumSize); + + qreal visualSize() const; + qreal visualPosition() const; + public Q_SLOTS: void setSize(qreal size); void setPosition(qreal position); @@ -94,6 +105,10 @@ Q_SIGNALS: void positionChanged(); void activeChanged(); void orientationChanged(); + // 2.4 (Qt 5.11) + Q_REVISION(4) void minimumSizeChanged(); + Q_REVISION(4) void visualSizeChanged(); + Q_REVISION(4) void visualPositionChanged(); protected: #if QT_CONFIG(quicktemplates2_multitouch) diff --git a/tests/auto/controls/data/tst_scrollindicator.qml b/tests/auto/controls/data/tst_scrollindicator.qml index a6275f91..9435ec3b 100644 --- a/tests/auto/controls/data/tst_scrollindicator.qml +++ b/tests/auto/controls/data/tst_scrollindicator.qml @@ -258,4 +258,52 @@ TestCase { touch.release(0, control).commit() verify(!ma.pressed) } + + function test_minimumSize() { + var container = createTemporaryObject(flickable, testCase) + verify(container) + waitForRendering(container) + + var vertical = scrollIndicator.createObject(container, {minimumSize: 0.1}) + container.ScrollIndicator.vertical = vertical + + compare(container.visibleArea.heightRatio, 0.5) + compare(vertical.size, 0.5) + compare(vertical.visualSize, 0.5) + compare(vertical.contentItem.height, 0.5 * vertical.availableHeight) + + container.contentHeight = 2000 + + compare(container.visibleArea.heightRatio, 0.05) + compare(vertical.size, 0.05) + compare(vertical.visualSize, 0.1) + compare(vertical.contentItem.height, 0.1 * vertical.availableHeight) + + verify(container.atYBeginning) + compare(container.visibleArea.yPosition, 0.0) + compare(vertical.position, 0.0) + compare(vertical.visualPosition, 0.0) + compare(vertical.contentItem.y, vertical.topPadding) + + container.contentY = 1900 + + verify(container.atYEnd) + compare(container.visibleArea.yPosition, 0.95) + compare(vertical.position, 0.95) + compare(vertical.visualPosition, 0.9) + compare(vertical.contentItem.y, vertical.topPadding + 0.9 * vertical.availableHeight) + + container.contentHeight = 125 + + compare(container.visibleArea.heightRatio, 0.8) + compare(vertical.size, 0.8) + compare(vertical.visualSize, 0.8) + compare(vertical.contentItem.height, 0.8 * vertical.availableHeight) + + verify(container.atYEnd) + compare(container.visibleArea.yPosition, 0.2) + compare(vertical.position, 0.2) + compare(vertical.visualPosition, 0.2) + compare(vertical.contentItem.y, vertical.topPadding + 0.2 * vertical.availableHeight) + } } |