From b16e7d2abcbb8558b5b4a85c7188c509bd7b9201 Mon Sep 17 00:00:00 2001 From: Andreas Eliasson Date: Thu, 2 Jun 2022 13:45:12 +0200 Subject: Doc: Fix link to Scrollbar size property The \l command with just one argument, size, has a competing section1 link target, Size, in a different C++ file. Specifying the C++ class as the first argument to the link command will make sure that the link goes to its intended target. Task-number: QTBUG-103250 Change-Id: I4c56685832b2b4b1772a8b63590c333f4f8e3ab5 Reviewed-by: Kai Koehne --- src/quicktemplates2/qquickscrollbar.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/quicktemplates2/qquickscrollbar.cpp b/src/quicktemplates2/qquickscrollbar.cpp index fea08b14..c9016cc9 100644 --- a/src/quicktemplates2/qquickscrollbar.cpp +++ b/src/quicktemplates2/qquickscrollbar.cpp @@ -77,7 +77,7 @@ QT_BEGIN_NAMESPACE \list \li \l orientation \li \l position - \li \l size + \li \l {ScrollBar::} {size} \li \l active \endlist -- cgit v1.2.3 From a272dffd15694fed53b615fb11a51159915d00f6 Mon Sep 17 00:00:00 2001 From: Shawn Rutledge Date: Tue, 7 Jun 2022 16:25:43 +0200 Subject: Take over touch grab after initial delayed mouse press from Flickable It has always caused a lot of trouble that Flickable only knows how to replay mouse events, not touch events, when pressDelay is set. Only the press is delayed; then if some recipient grabs (e.g. by accepting the mouse event), it grabs the underlying touch point ID, and thus the following touch moves and release will be sent to it as QTouchEvents. So, delegates in itemviews receive touch presses as mouse events, and then touch events; and perhaps it's risky to assume that's all the same sequence just because pressWasTouch got set to true, but now we do it under either of two conditions: touch release occurs near the mouse press, or the touch has been dragged past the drag threshold. (The real fix is in Qt 6: Flickable knows how to replay touch events.) Amends and extends 025f938c1b4676782674d54375e1e4e560e4b6cd and fcc3d346c8aaff74b0054974040d3c1250301563 Task-number: QTBUG-77202 Fixes: QTBUG-104009 Change-Id: I7e1980e2fbc9b7a1b53c56409fb8a7adc424d61c Reviewed-by: Mitch Curtis --- src/quicktemplates2/qquickcontrol.cpp | 15 ++++++++++---- tests/auto/controls/data/tst_slider.qml | 35 +++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/quicktemplates2/qquickcontrol.cpp b/src/quicktemplates2/qquickcontrol.cpp index 2c9fb71f..ac1303a2 100644 --- a/src/quicktemplates2/qquickcontrol.cpp +++ b/src/quicktemplates2/qquickcontrol.cpp @@ -177,12 +177,19 @@ bool QQuickControlPrivate::acceptTouch(const QTouchEvent::TouchPoint &point) return true; } - // If the control is on a Flickable that has a pressDelay, then the press is never - // sent as a touch event, therefore we need to check for this case. - if (touchId == -1 && pressWasTouch && point.state() == Qt::TouchPointReleased) { + // If the control is on a Flickable that has a pressDelay, the press is sent + // as a mouse event rather than touch; so it detect and deal with it. + if (touchId == -1 && pressWasTouch) { const auto delta = QVector2D(point.pos() - previousPressPos); - if (!QQuickWindowPrivate::dragOverThreshold(delta)) + const bool overThreshold = QQuickWindowPrivate::dragOverThreshold(delta); + if (point.state() == Qt::TouchPointReleased && !overThreshold) { + // touchpoint was released near the press position: don't expect any more events, but just handle the release return true; + } else if (point.state() == Qt::TouchPointMoved && overThreshold) { + // touchpoint was dragged over the drag threshold: accept it, and remember to handle all moves from now on + touchId = point.id(); + return true; + } } return false; } diff --git a/tests/auto/controls/data/tst_slider.qml b/tests/auto/controls/data/tst_slider.qml index e1e1ed97..bf65e486 100644 --- a/tests/auto/controls/data/tst_slider.qml +++ b/tests/auto/controls/data/tst_slider.qml @@ -923,4 +923,39 @@ TestCase { touch.release(0, control, x0 + data.dx2, y0 + data.dy2).commit() } + + Component { + id: listViewWithPressDelayAndSliders + ListView { + width: 300 + height: 500 + model: 3 + pressDelay: 150 + delegate: Slider { + width: 300 + height: 150 + } + } + } + + function test_listViewWithPressDelay() { + var listView = createTemporaryObject(listViewWithPressDelayAndSliders, testCase, { width: parent.width, height: parent.height }) + verify(listView) + var control = listView.itemAtIndex(0) + verify(control) + var movedSpy = signalSpy.createObject(control, {target: control, signalName: "moved"}) + verify(movedSpy.valid) + + var touch = touchEvent(control) + var x0 = control.handle.x + control.handle.width * 0.5 + var y0 = control.handle.y + control.handle.height * 0.5 + touch.press(0, control, x0, y0).commit() + tryCompare(control, "pressed", true) + fuzzyCompare(control.value, 0, 0.01) + + touch.move(0, control, x0 + 100, y0).commit() + tryVerify(function() { return (control.value > 0.3); }) // around 0.35, depending on style + tryVerify(function() { return (movedSpy.count > 0); }) // ideally == 1, but in Material and Fusion it's 2 + touch.release(0) + } } -- cgit v1.2.3 From e6d7494b64325614a3de77296a60f0769f59bc15 Mon Sep 17 00:00:00 2001 From: Tarja Sundqvist Date: Wed, 15 Jun 2022 20:09:12 +0300 Subject: Bump version --- .qmake.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.qmake.conf b/.qmake.conf index edff2782..6279b0c5 100644 --- a/.qmake.conf +++ b/.qmake.conf @@ -5,4 +5,4 @@ DEFINES += QT_NO_FOREACH QT_NO_JAVA_STYLE_ITERATORS QT_NO_LINKED_LIST QQC2_SOURCE_TREE = $$PWD -MODULE_VERSION = 5.15.10 +MODULE_VERSION = 5.15.11 -- cgit v1.2.3 From 56acab014d490951f14e6719b7bd535146646fc7 Mon Sep 17 00:00:00 2001 From: Mitch Curtis Date: Fri, 19 Aug 2022 12:01:56 +0800 Subject: Fix scroll bars not showing up when binding to standalone contentItem 908aa77d16e00f2bccc0ddae0f8b61955c56a6a1 hid old scroll bars, but didn't account for the situation where the old scroll bars would be put back into place, and so they never showed up. In the case of the linked bug report, since there was a binding to the ScrollView's contentItem, a default Flickable would be created. After that binding was evaluated, the contentItem was set, causing the scroll bars to be hidden (as part of the process of disconnecting from the old flickable). To fix the issue, we now do the reverse of hideOldItem when a new contentItem is set. Fixes: QTBUG-104983 Reviewed-by: Fabian Kosmale Reviewed-by: Nate Graham (cherry picked from commit 58bae53237417f28eac6d772fa6ecab657f8a73f) Change-Id: I0d5d04cf9268e03b99c8b8fba2eee407e225ae56 --- src/quicktemplates2/qquickcontrol.cpp | 30 ++++++++++++++++++ src/quicktemplates2/qquickcontrol_p_p.h | 1 + src/quicktemplates2/qquickscrollbar.cpp | 11 +++++++ src/quicktemplates2/qquickscrollbar_p_p.h | 2 ++ tests/auto/controls/data/tst_scrollview.qml | 47 +++++++++++++++++++++++++++++ 5 files changed, 91 insertions(+) diff --git a/src/quicktemplates2/qquickcontrol.cpp b/src/quicktemplates2/qquickcontrol.cpp index ac1303a2..23ebf345 100644 --- a/src/quicktemplates2/qquickcontrol.cpp +++ b/src/quicktemplates2/qquickcontrol.cpp @@ -853,6 +853,13 @@ void QQuickControlPrivate::executeBackground(bool complete) quickCompleteDeferred(q, backgroundName(), background); } +/* + \internal + + Hides an item that was replaced by a newer one, rather than + deleting it, as the item is typically created in QML and hence + we don't own it. +*/ void QQuickControlPrivate::hideOldItem(QQuickItem *item) { if (!item) @@ -871,6 +878,29 @@ void QQuickControlPrivate::hideOldItem(QQuickItem *item) #endif } +/* + \internal + + Named "unhide" because it's used for cases where an item + that was previously hidden by \l hideOldItem() wants to be + shown by a control again, such as a ScrollBar in ScrollView. +*/ +void QQuickControlPrivate::unhideOldItem(QQuickControl *control, QQuickItem *item) +{ + Q_ASSERT(item); + qCDebug(lcItemManagement) << "unhiding old item" << item; + + item->setVisible(true); + item->setParentItem(control); + +#if QT_CONFIG(accessibility) + // Add the item back in to the accessibility tree. + QQuickAccessibleAttached *accessible = accessibleAttached(item); + if (accessible) + accessible->setIgnored(false); +#endif +} + void QQuickControlPrivate::updateBaselineOffset() { Q_Q(QQuickControl); diff --git a/src/quicktemplates2/qquickcontrol_p_p.h b/src/quicktemplates2/qquickcontrol_p_p.h index aca6d03f..a923aa18 100644 --- a/src/quicktemplates2/qquickcontrol_p_p.h +++ b/src/quicktemplates2/qquickcontrol_p_p.h @@ -173,6 +173,7 @@ public: virtual void executeBackground(bool complete = false); static void hideOldItem(QQuickItem *item); + static void unhideOldItem(QQuickControl *control, QQuickItem *item); void updateBaselineOffset(); diff --git a/src/quicktemplates2/qquickscrollbar.cpp b/src/quicktemplates2/qquickscrollbar.cpp index c9016cc9..ec647407 100644 --- a/src/quicktemplates2/qquickscrollbar.cpp +++ b/src/quicktemplates2/qquickscrollbar.cpp @@ -797,6 +797,14 @@ void QQuickScrollBarAttachedPrivate::initHorizontal() if (parent && parent == flickable->parentItem()) horizontal->stackAfter(flickable); + // If a scroll bar was previously hidden (due to e.g. setting a new contentItem + // on a ScrollView), we need to make sure that we un-hide it. + // We don't bother checking if the item is actually the old one, because + // if it's not, all of the things the function does (setting parent, visibility, etc.) + // should be no-ops anyway. + if (auto control = qobject_cast(q_func()->parent())) + QQuickControlPrivate::unhideOldItem(control, horizontal); + layoutHorizontal(); horizontal->setSize(area->property("widthRatio").toReal()); horizontal->setPosition(area->property("xPosition").toReal()); @@ -818,6 +826,9 @@ void QQuickScrollBarAttachedPrivate::initVertical() if (parent && parent == flickable->parentItem()) vertical->stackAfter(flickable); + if (auto control = qobject_cast(q_func()->parent())) + QQuickControlPrivate::unhideOldItem(control, vertical); + layoutVertical(); vertical->setSize(area->property("heightRatio").toReal()); vertical->setPosition(area->property("yPosition").toReal()); diff --git a/src/quicktemplates2/qquickscrollbar_p_p.h b/src/quicktemplates2/qquickscrollbar_p_p.h index 6841ec73..bbb5f6c1 100644 --- a/src/quicktemplates2/qquickscrollbar_p_p.h +++ b/src/quicktemplates2/qquickscrollbar_p_p.h @@ -107,6 +107,8 @@ public: class QQuickScrollBarAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener { + Q_DECLARE_PUBLIC(QQuickScrollBar) + public: static QQuickScrollBarAttachedPrivate *get(QQuickScrollBarAttached *attached) { diff --git a/tests/auto/controls/data/tst_scrollview.qml b/tests/auto/controls/data/tst_scrollview.qml index 0e8b0835..cd493118 100644 --- a/tests/auto/controls/data/tst_scrollview.qml +++ b/tests/auto/controls/data/tst_scrollview.qml @@ -576,4 +576,51 @@ TestCase { verify(newHorizontalScrollBar.visible) verify(!oldHorizontalScrollBar.visible) } + + Component { + id: bindingToContentItemAndStandaloneFlickable + + Item { + width: 200 + height: 200 + + property alias scrollView: scrollView + + ScrollView { + id: scrollView + anchors.fill: parent + contentItem: listView + + property Item someBinding: contentItem + } + ListView { + id: listView + model: 10 + delegate: ItemDelegate { + text: modelData + width: listView.width + } + } + } + } + + // Tests that scroll bars show up for a ScrollView where + // - its contentItem is declared as a standalone, separate item + // - there is a binding to contentItem (which causes a default Flickable to be created) + function test_bindingToContentItemAndStandaloneFlickable() { + let root = createTemporaryObject(bindingToContentItemAndStandaloneFlickable, testCase) + verify(root) + + let control = root.scrollView + let verticalScrollBar = control.ScrollBar.vertical + let horizontalScrollBar = control.ScrollBar.horizontal + compare(verticalScrollBar.parent, control) + compare(horizontalScrollBar.parent, control) + verify(verticalScrollBar.visible) + verify(horizontalScrollBar.visible) + + mouseDrag(verticalScrollBar, verticalScrollBar.width / 2, verticalScrollBar.height / 2, 0, 50) + verify(verticalScrollBar.active) + verify(horizontalScrollBar.active) + } } -- cgit v1.2.3