diff options
Diffstat (limited to 'src')
97 files changed, 1353 insertions, 272 deletions
diff --git a/src/imports/controls/ComboBox.qml b/src/imports/controls/ComboBox.qml index b30293f5..e9f93d66 100644 --- a/src/imports/controls/ComboBox.qml +++ b/src/imports/controls/ComboBox.qml @@ -53,7 +53,7 @@ T.ComboBox { rightPadding: padding + (control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing) delegate: ItemDelegate { - width: parent.width + width: ListView.view.width text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData palette.text: control.palette.text palette.highlightedText: control.palette.highlightedText diff --git a/src/imports/controls/DialogButtonBox.qml b/src/imports/controls/DialogButtonBox.qml index 3c9d5b48..cc148ac4 100644 --- a/src/imports/controls/DialogButtonBox.qml +++ b/src/imports/controls/DialogButtonBox.qml @@ -55,6 +55,7 @@ T.DialogButtonBox { } contentItem: ListView { + implicitWidth: contentWidth model: control.contentModel spacing: control.spacing orientation: ListView.Horizontal diff --git a/src/imports/controls/designer/AbstractButtonSection.qml b/src/imports/controls/designer/AbstractButtonSection.qml index e8aa39c2..35fad2ab 100644 --- a/src/imports/controls/designer/AbstractButtonSection.qml +++ b/src/imports/controls/designer/AbstractButtonSection.qml @@ -104,8 +104,8 @@ Section { } Label { - text: qsTr("Repeat") - tooltip: qsTr("Whether the button repeats while pressed and held down.") + text: qsTr("Auto-Repeat") + tooltip: qsTr("Whether the button repeats pressed(), released() and clicked() signals while the button is pressed and held down.") } SecondColumnLayout { CheckBox { diff --git a/src/imports/controls/designer/ButtonSection.qml b/src/imports/controls/designer/ButtonSection.qml index fef46071..951c8cf4 100644 --- a/src/imports/controls/designer/ButtonSection.qml +++ b/src/imports/controls/designer/ButtonSection.qml @@ -43,17 +43,7 @@ Section { caption: qsTr("Button") SectionLayout { - Label { - text: qsTr("AutoRepeat") - tooltip: qsTr("Whether the button repeats pressed(), released() and clicked() signals while the button is pressed and held down.") - } - SecondColumnLayout { - CheckBox { - text: backendValues.autoRepeat.valueToString - backendValue: backendValues.autoRepeat - Layout.fillWidth: true - } - } + Label { text: qsTr("Flat") tooltip: qsTr("Whether the button is flat.") diff --git a/src/imports/controls/designer/ControlSection.qml b/src/imports/controls/designer/ControlSection.qml index 7c53ac73..3446c08f 100644 --- a/src/imports/controls/designer/ControlSection.qml +++ b/src/imports/controls/designer/ControlSection.qml @@ -69,7 +69,7 @@ Section { Label { text: qsTr("Hover") - tooltip: qsTr("Whether control accepts hover evets.") + tooltip: qsTr("Whether control accepts hover events.") } SecondColumnLayout { CheckBox { @@ -95,7 +95,7 @@ Section { Label { text: qsTr("Wheel") - tooltip: qsTr("Whether control accepts wheel evets.") + tooltip: qsTr("Whether control accepts wheel events.") } SecondColumnLayout { CheckBox { diff --git a/src/imports/controls/designer/DialSpecifics.qml b/src/imports/controls/designer/DialSpecifics.qml index fc5b5e83..a0df81ef 100644 --- a/src/imports/controls/designer/DialSpecifics.qml +++ b/src/imports/controls/designer/DialSpecifics.qml @@ -112,7 +112,7 @@ Column { } SecondColumnLayout { ComboBox { - backendValue: backendValues.orientation + backendValue: backendValues.snapMode model: [ "NoSnap", "SnapOnRelease", "SnapAlways" ] scope: "Dial" Layout.fillWidth: true @@ -143,6 +143,18 @@ Column { Layout.fillWidth: true } } + + Label { + text: qsTr("Wrap") + tooltip: qsTr("Whether the dial wraps when dragged.") + } + SecondColumnLayout { + CheckBox { + text: backendValues.wrap.valueToString + backendValue: backendValues.wrap + Layout.fillWidth: true + } + } } } diff --git a/src/imports/controls/designer/InsetSection.qml b/src/imports/controls/designer/InsetSection.qml new file mode 100644 index 00000000..4253b170 --- /dev/null +++ b/src/imports/controls/designer/InsetSection.qml @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2020 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$ +** +****************************************************************************/ + +import QtQuick 2.12 +import HelperWidgets 2.0 +import QtQuick.Layouts 1.12 + +Section { + caption: qsTr("Inset") + + SectionLayout { + Label { + text: qsTr("Vertical") + } + SecondColumnLayout { + Label { + text: qsTr("Top") + tooltip: qsTr("Top inset for the background.") + width: 42 + } + SpinBox { + maximumValue: 10000 + minimumValue: -10000 + realDragRange: 5000 + decimals: 0 + backendValue: backendValues.topInset + Layout.fillWidth: true + } + Item { + width: 4 + height: 4 + } + + Label { + text: qsTr("Bottom") + tooltip: qsTr("Bottom inset for the background.") + width: 42 + } + SpinBox { + maximumValue: 10000 + minimumValue: -10000 + realDragRange: 5000 + decimals: 0 + backendValue: backendValues.bottomInset + Layout.fillWidth: true + } + } + + Label { + text: qsTr("Horizontal") + } + SecondColumnLayout { + Label { + text: qsTr("Left") + tooltip: qsTr("Left inset for the background.") + width: 42 + } + SpinBox { + maximumValue: 10000 + minimumValue: -10000 + realDragRange: 5000 + decimals: 0 + backendValue: backendValues.leftInset + Layout.fillWidth: true + } + Item { + width: 4 + height: 4 + } + + Label { + text: qsTr("Right") + tooltip: qsTr("Right inset for the background.") + width: 42 + } + SpinBox { + maximumValue: 10000 + minimumValue: -10000 + realDragRange: 5000 + decimals: 0 + backendValue: backendValues.rightInset + Layout.fillWidth: true + } + } + } +} diff --git a/src/imports/controls/designer/LabelSpecifics.qml b/src/imports/controls/designer/LabelSpecifics.qml index c832f894..e5d5e04f 100644 --- a/src/imports/controls/designer/LabelSpecifics.qml +++ b/src/imports/controls/designer/LabelSpecifics.qml @@ -79,4 +79,8 @@ Column { PaddingSection { width: parent.width } + + InsetSection { + width: parent.width + } } diff --git a/src/imports/controls/designer/PageIndicatorSpecifics.qml b/src/imports/controls/designer/PageIndicatorSpecifics.qml index 042672a9..20aa8577 100644 --- a/src/imports/controls/designer/PageIndicatorSpecifics.qml +++ b/src/imports/controls/designer/PageIndicatorSpecifics.qml @@ -73,6 +73,18 @@ Column { Layout.fillWidth: true } } + + Label { + text: qsTr("Interactive") + tooltip: qsTr("Whether the control is interactive.") + } + SecondColumnLayout { + CheckBox { + text: backendValues.interactive.valueToString + backendValue: backendValues.interactive + Layout.fillWidth: true + } + } } } @@ -80,10 +92,6 @@ Column { width: parent.width } - FontSection { - width: parent.width - } - PaddingSection { width: parent.width } diff --git a/src/imports/controls/designer/RangeSliderSpecifics.qml b/src/imports/controls/designer/RangeSliderSpecifics.qml index 79d2404f..9372a4ff 100644 --- a/src/imports/controls/designer/RangeSliderSpecifics.qml +++ b/src/imports/controls/designer/RangeSliderSpecifics.qml @@ -127,7 +127,7 @@ Column { } SecondColumnLayout { ComboBox { - backendValue: backendValues.orientation + backendValue: backendValues.snapMode model: [ "NoSnap", "SnapOnRelease", "SnapAlways" ] scope: "RangeSlider" Layout.fillWidth: true @@ -158,6 +158,20 @@ Column { Layout.fillWidth: true } } + + Label { + text: qsTr("Touch drag threshold") + tooltip: qsTr("The threshold (in logical pixels) at which a touch drag event will be initiated.") + } + SecondColumnLayout { + SpinBox { + minimumValue: 0 + maximumValue: 10000 + decimals: 0 + backendValue: backendValues.touchDragThreshold + Layout.fillWidth: true + } + } } } diff --git a/src/imports/controls/designer/RoundButtonSpecifics.qml b/src/imports/controls/designer/RoundButtonSpecifics.qml index 2da4cda6..af4ab5d0 100644 --- a/src/imports/controls/designer/RoundButtonSpecifics.qml +++ b/src/imports/controls/designer/RoundButtonSpecifics.qml @@ -42,6 +42,7 @@ Column { width: parent.width Section { + width: parent.width caption: qsTr("RoundButton") SectionLayout { @@ -51,8 +52,8 @@ Column { } SecondColumnLayout { SpinBox { - maximumValue: 9999999 - minimumValue: -9999999 + minimumValue: 0 + maximumValue: 10000 decimals: 0 backendValue: backendValues.radius Layout.fillWidth: true diff --git a/src/imports/controls/designer/SliderSpecifics.qml b/src/imports/controls/designer/SliderSpecifics.qml index 076d8a1c..d126dd06 100644 --- a/src/imports/controls/designer/SliderSpecifics.qml +++ b/src/imports/controls/designer/SliderSpecifics.qml @@ -143,6 +143,20 @@ Column { Layout.fillWidth: true } } + + Label { + text: qsTr("Touch drag threshold") + tooltip: qsTr("The threshold (in logical pixels) at which a touch drag event will be initiated.") + } + SecondColumnLayout { + SpinBox { + minimumValue: 0 + maximumValue: 10000 + decimals: 0 + backendValue: backendValues.touchDragThreshold + Layout.fillWidth: true + } + } } } diff --git a/src/imports/controls/designer/SpinBoxSpecifics.qml b/src/imports/controls/designer/SpinBoxSpecifics.qml index d6375d7c..db59f074 100644 --- a/src/imports/controls/designer/SpinBoxSpecifics.qml +++ b/src/imports/controls/designer/SpinBoxSpecifics.qml @@ -113,6 +113,18 @@ Column { Layout.fillWidth: true } } + + Label { + text: qsTr("Wrap") + tooltip: qsTr("Whether the spinbox wraps.") + } + SecondColumnLayout { + CheckBox { + text: backendValues.wrap.valueToString + backendValue: backendValues.wrap + Layout.fillWidth: true + } + } } } diff --git a/src/imports/controls/designer/TextAreaSpecifics.qml b/src/imports/controls/designer/TextAreaSpecifics.qml index a14584e7..f8cf92e8 100644 --- a/src/imports/controls/designer/TextAreaSpecifics.qml +++ b/src/imports/controls/designer/TextAreaSpecifics.qml @@ -57,6 +57,29 @@ Column { } } + + Label { + text: qsTr("Hover") + tooltip: qsTr("Whether text area accepts hover events.") + } + SecondColumnLayout { + CheckBox { + text: backendValues.hoverEnabled.valueToString + backendValue: backendValues.hoverEnabled + Layout.fillWidth: true + } + } + } + } + + Section { + width: parent.width + caption: qsTr("Placeholder Text Color") + + ColorEditor { + caption: qsTr("Placeholder Text Color") + backendValue: backendValues.placeholderTextColor + supportGradient: false } } @@ -74,4 +97,8 @@ Column { PaddingSection { width: parent.width } + + InsetSection { + width: parent.width + } } diff --git a/src/imports/controls/designer/TextFieldSpecifics.qml b/src/imports/controls/designer/TextFieldSpecifics.qml index 67a63ec4..f95f282c 100644 --- a/src/imports/controls/designer/TextFieldSpecifics.qml +++ b/src/imports/controls/designer/TextFieldSpecifics.qml @@ -57,6 +57,29 @@ Column { } } + + Label { + text: qsTr("Hover") + tooltip: qsTr("Whether text field accepts hover events.") + } + SecondColumnLayout { + CheckBox { + text: backendValues.hoverEnabled.valueToString + backendValue: backendValues.hoverEnabled + Layout.fillWidth: true + } + } + } + } + + Section { + width: parent.width + caption: qsTr("Placeholder Text Color") + + ColorEditor { + caption: qsTr("Placeholder Text Color") + backendValue: backendValues.placeholderTextColor + supportGradient: false } } @@ -71,4 +94,8 @@ Column { PaddingSection { width: parent.width } + + InsetSection { + width: parent.width + } } diff --git a/src/imports/controls/designer/designer.pri b/src/imports/controls/designer/designer.pri index 3ad99df7..6692b203 100644 --- a/src/imports/controls/designer/designer.pri +++ b/src/imports/controls/designer/designer.pri @@ -17,6 +17,7 @@ AUX_QML_FILES += \ $$PWD/DialSpecifics.qml \ $$PWD/FrameSpecifics.qml \ $$PWD/GroupBoxSpecifics.qml \ + $$PWD/InsetSection.qml \ $$PWD/ItemDelegateSection.qml \ $$PWD/ItemDelegateSpecifics.qml \ $$PWD/LabelSpecifics.qml \ diff --git a/src/imports/controls/doc/src/includes/qquickicon.qdocinc b/src/imports/controls/doc/src/includes/qquickicon.qdocinc index ba7cede9..beef5624 100644 --- a/src/imports/controls/doc/src/includes/qquickicon.qdocinc +++ b/src/imports/controls/doc/src/includes/qquickicon.qdocinc @@ -44,5 +44,7 @@ \li This property specifies whether the icon should be cached. The default value is true. + + This property was introduced in QtQuick.Controls 2.13. \endtable //! [grouped-properties] diff --git a/src/imports/controls/doc/src/qtquickcontrols2-icons.qdoc b/src/imports/controls/doc/src/qtquickcontrols2-icons.qdoc index f8cb1f52..190aafd9 100644 --- a/src/imports/controls/doc/src/qtquickcontrols2-icons.qdoc +++ b/src/imports/controls/doc/src/qtquickcontrols2-icons.qdoc @@ -44,6 +44,7 @@ \li \c icon.width \li \c icon.height \li \c icon.color + \li \c icon.cache \endlist Theme icons are referenced by a name, and regular icons by a source URL. Both diff --git a/src/imports/controls/fusion/ComboBox.qml b/src/imports/controls/fusion/ComboBox.qml index d8ef1888..5e26f90e 100644 --- a/src/imports/controls/fusion/ComboBox.qml +++ b/src/imports/controls/fusion/ComboBox.qml @@ -55,7 +55,7 @@ T.ComboBox { rightPadding: padding + (control.mirrored || !indicator || !indicator.visible ? 0 : indicator.width + spacing) delegate: MenuItem { - width: parent.width + width: ListView.view.width text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal highlighted: control.highlightedIndex === index diff --git a/src/imports/controls/fusion/DialogButtonBox.qml b/src/imports/controls/fusion/DialogButtonBox.qml index a0b0f243..4673e421 100644 --- a/src/imports/controls/fusion/DialogButtonBox.qml +++ b/src/imports/controls/fusion/DialogButtonBox.qml @@ -56,6 +56,7 @@ T.DialogButtonBox { delegate: Button { } contentItem: ListView { + implicitWidth: contentWidth model: control.contentModel spacing: control.spacing orientation: ListView.Horizontal diff --git a/src/imports/controls/fusion/plugins.qmltypes b/src/imports/controls/fusion/plugins.qmltypes index 5140d1e8..681b8b90 100644 --- a/src/imports/controls/fusion/plugins.qmltypes +++ b/src/imports/controls/fusion/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.Controls.Fusion 2.14' +// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.Controls.Fusion 2.15' Module { dependencies: ["QtQuick.Controls 2.0"] diff --git a/src/imports/controls/imagine/ComboBox.qml b/src/imports/controls/imagine/ComboBox.qml index 92937826..d657e734 100644 --- a/src/imports/controls/imagine/ComboBox.qml +++ b/src/imports/controls/imagine/ComboBox.qml @@ -59,7 +59,7 @@ T.ComboBox { bottomInset: background ? -background.bottomInset || 0 : 0 delegate: ItemDelegate { - width: parent.width + width: ListView.view.width text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal highlighted: control.highlightedIndex === index diff --git a/src/imports/controls/imagine/DialogButtonBox.qml b/src/imports/controls/imagine/DialogButtonBox.qml index c24b29fc..fd27a876 100644 --- a/src/imports/controls/imagine/DialogButtonBox.qml +++ b/src/imports/controls/imagine/DialogButtonBox.qml @@ -66,6 +66,7 @@ T.DialogButtonBox { } contentItem: ListView { + implicitWidth: contentWidth model: control.contentModel spacing: control.spacing orientation: ListView.Horizontal diff --git a/src/imports/controls/imagine/GroupBox.qml b/src/imports/controls/imagine/GroupBox.qml index 7abdb6f0..46f9c98a 100644 --- a/src/imports/controls/imagine/GroupBox.qml +++ b/src/imports/controls/imagine/GroupBox.qml @@ -53,7 +53,6 @@ T.GroupBox { leftPadding: background ? background.leftPadding : 0 rightPadding: background ? background.rightPadding : 0 bottomPadding: background ? background.bottomPadding : 0 - padding: 12 label: Label { width: control.width @@ -88,7 +87,7 @@ T.GroupBox { x: -leftInset y: control.topPadding - control.bottomPadding - topInset width: control.width + leftInset + rightInset - height: control.height + topInset + bottomInset - control.topPadding + control.padding + height: control.height + topInset + bottomInset - control.topPadding + control.bottomPadding source: Imagine.url + "groupbox-background" NinePatchImageSelector on source { diff --git a/src/imports/controls/imagine/plugins.qmltypes b/src/imports/controls/imagine/plugins.qmltypes index 191807ae..785b6dba 100644 --- a/src/imports/controls/imagine/plugins.qmltypes +++ b/src/imports/controls/imagine/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.Controls.Imagine 2.14' +// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.Controls.Imagine 2.15' Module { dependencies: ["QtQuick.Controls 2.0"] @@ -54,6 +54,7 @@ Module { Property { name: "verticalAlignment"; type: "VAlignment" } Property { name: "mipmap"; revision: 3; type: "bool" } Property { name: "autoTransform"; revision: 5; type: "bool" } + Property { name: "sourceClipRect"; revision: 15; type: "QRectF" } Signal { name: "paintedGeometryChanged" } Signal { name: "horizontalAlignmentChanged" @@ -75,6 +76,14 @@ Module { defaultProperty: "data" prototype: "QQuickImplicitSizeItem" Enum { + name: "LoadPixmapOptions" + values: { + "NoOption": 0, + "HandleDPR": 1, + "UseProviderOptions": 2 + } + } + Enum { name: "Status" values: { "Null": 0, @@ -92,6 +101,7 @@ Module { Property { name: "mirror"; type: "bool" } Property { name: "currentFrame"; revision: 14; type: "int" } Property { name: "frameCount"; revision: 14; type: "int"; isReadonly: true } + Property { name: "colorSpace"; revision: 15; type: "QColorSpace" } Signal { name: "sourceChanged" Parameter { type: "QUrl" } @@ -106,6 +116,8 @@ Module { } Signal { name: "currentFrameChanged"; revision: 14 } Signal { name: "frameCountChanged"; revision: 14 } + Signal { name: "sourceClipRectChanged"; revision: 15 } + Signal { name: "colorSpaceChanged"; revision: 15 } } Component { name: "QQuickImageSelector" diff --git a/src/imports/controls/imagine/qquickninepatchimage.cpp b/src/imports/controls/imagine/qquickninepatchimage.cpp index 7d5e4f71..ed388ec1 100644 --- a/src/imports/controls/imagine/qquickninepatchimage.cpp +++ b/src/imports/controls/imagine/qquickninepatchimage.cpp @@ -386,7 +386,12 @@ void QQuickNinePatchImage::pixmapChange() { Q_D(QQuickNinePatchImage); if (QFileInfo(d->url.fileName()).completeSuffix().toLower() == QLatin1String("9.png")) { - d->resetNode = d->ninePatch.isNull(); + // Keep resetNode if it is already set, we do not want to miss an + // ImageNode->NinePatchNode change. Without this there's a chance one gets + // an incorrect cast on oldNode every once in a while with source changes. + if (!d->resetNode) + d->resetNode = d->ninePatch.isNull(); + d->ninePatch = d->pix.image(); if (d->ninePatch.depth() != 32) d->ninePatch = d->ninePatch.convertToFormat(QImage::Format_ARGB32); @@ -434,6 +439,8 @@ QSGNode *QQuickNinePatchImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNode QSizeF sz = size(); QImage image = d->pix.image(); if (!sz.isValid() || image.isNull()) { + if (d->provider) + d->provider->updateTexture(nullptr); delete oldNode; return nullptr; } @@ -449,6 +456,13 @@ QSGNode *QQuickNinePatchImage::updatePaintNode(QSGNode *oldNode, UpdatePaintNode qsgnode_set_description(patchNode, QString::fromLatin1("QQuickNinePatchImage: '%1'").arg(d->url.toString())); #endif + // The image may wrap non-owned data (due to pixmapChange). Ensure we never + // pass such an image to the scenegraph, because with a separate render + // thread the data may become invalid (in a subsequent pixmapChange on the + // gui thread) by the time the renderer gets to do something with the QImage + // passed in here. + image.detach(); + QSGTexture *texture = window()->createTextureFromImage(image); patchNode->initialize(texture, sz * d->devicePixelRatio, image.size(), d->xDivs, d->yDivs, d->devicePixelRatio); return patchNode; diff --git a/src/imports/controls/material/ComboBox.qml b/src/imports/controls/material/ComboBox.qml index e4ee332b..6aada8c5 100644 --- a/src/imports/controls/material/ComboBox.qml +++ b/src/imports/controls/material/ComboBox.qml @@ -63,9 +63,9 @@ T.ComboBox { Material.foreground: flat ? undefined : Material.primaryTextColor delegate: MenuItem { - width: parent.width + width: ListView.view.width text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData - Material.foreground: control.currentIndex === index ? parent.Material.accent : parent.Material.foreground + Material.foreground: control.currentIndex === index ? ListView.view.contentItem.Material.accent : ListView.view.contentItem.Material.foreground highlighted: control.highlightedIndex === index hoverEnabled: control.hoverEnabled } @@ -147,14 +147,14 @@ T.ComboBox { enter: Transition { // grow_fade_in - NumberAnimation { property: "scale"; from: 0.9; to: 1.0; easing.type: Easing.OutQuint; duration: 220 } - NumberAnimation { property: "opacity"; from: 0.0; to: 1.0; easing.type: Easing.OutCubic; duration: 150 } + NumberAnimation { property: "scale"; from: 0.9; easing.type: Easing.OutQuint; duration: 220 } + NumberAnimation { property: "opacity"; from: 0.0; easing.type: Easing.OutCubic; duration: 150 } } exit: Transition { // shrink_fade_out - NumberAnimation { property: "scale"; from: 1.0; to: 0.9; easing.type: Easing.OutQuint; duration: 220 } - NumberAnimation { property: "opacity"; from: 1.0; to: 0.0; easing.type: Easing.OutCubic; duration: 150 } + NumberAnimation { property: "scale"; to: 0.9; easing.type: Easing.OutQuint; duration: 220 } + NumberAnimation { property: "opacity"; to: 0.0; easing.type: Easing.OutCubic; duration: 150 } } contentItem: ListView { diff --git a/src/imports/controls/material/DialogButtonBox.qml b/src/imports/controls/material/DialogButtonBox.qml index c53b8210..d148fb24 100644 --- a/src/imports/controls/material/DialogButtonBox.qml +++ b/src/imports/controls/material/DialogButtonBox.qml @@ -60,6 +60,7 @@ T.DialogButtonBox { delegate: Button { flat: true } contentItem: ListView { + implicitWidth: contentWidth model: control.contentModel spacing: control.spacing orientation: ListView.Horizontal diff --git a/src/imports/controls/material/material.pro b/src/imports/controls/material/material.pro index cf08b925..ea74d277 100644 --- a/src/imports/controls/material/material.pro +++ b/src/imports/controls/material/material.pro @@ -1,4 +1,4 @@ -TARGET = qtquickcontrols2materialstyleplugin +TARGET = qqc2materialstyleplugin TARGETPATH = QtQuick/Controls.2/Material IMPORT_NAME = QtQuick.Controls.Material diff --git a/src/imports/controls/material/plugins.qmltypes b/src/imports/controls/material/plugins.qmltypes index 7546a7b0..e290e0ea 100644 --- a/src/imports/controls/material/plugins.qmltypes +++ b/src/imports/controls/material/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.Controls.Material 2.14' +// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.Controls.Material 2.15' Module { dependencies: ["QtQuick.Controls 2.0"] @@ -328,6 +328,7 @@ Module { Property { name: "toolBarColor"; type: "QColor"; isReadonly: true } Property { name: "toolTextColor"; type: "QColor"; isReadonly: true } Property { name: "spinBoxDisabledIconColor"; type: "QColor"; isReadonly: true } + Property { name: "sliderDisabledColor"; revision: 15; type: "QColor"; isReadonly: true } Property { name: "touchTarget"; type: "int"; isReadonly: true } Property { name: "buttonHeight"; type: "int"; isReadonly: true } Property { name: "delegateHeight"; type: "int"; isReadonly: true } diff --git a/src/imports/controls/material/qmldir b/src/imports/controls/material/qmldir index 870a0382..d48b7b12 100644 --- a/src/imports/controls/material/qmldir +++ b/src/imports/controls/material/qmldir @@ -1,4 +1,4 @@ module QtQuick.Controls.Material -plugin qtquickcontrols2materialstyleplugin +plugin qqc2materialstyleplugin classname QtQuickControls2MaterialStylePlugin depends QtQuick.Controls 2.5 diff --git a/src/imports/controls/material/qquickmaterialstyle.cpp b/src/imports/controls/material/qquickmaterialstyle.cpp index 35afeb00..d343f2f5 100644 --- a/src/imports/controls/material/qquickmaterialstyle.cpp +++ b/src/imports/controls/material/qquickmaterialstyle.cpp @@ -469,14 +469,13 @@ void QQuickMaterialStyle::setTheme(Theme theme) m_theme = theme; propagateTheme(); - emit themeChanged(); - emit paletteChanged(); + themeChange(); if (!m_customAccent) - emit accentChanged(); + accentChange(); if (!m_hasBackground) - emit backgroundChanged(); + backgroundChange(); if (!m_hasForeground) - emit foregroundChanged(); + foregroundChange(); } void QQuickMaterialStyle::inheritTheme(Theme theme) @@ -486,14 +485,13 @@ void QQuickMaterialStyle::inheritTheme(Theme theme) m_theme = theme; propagateTheme(); - emit themeChanged(); - emit paletteChanged(); + themeChange(); if (!m_customAccent) - emit accentChanged(); + accentChange(); if (!m_hasBackground) - emit backgroundChanged(); + backgroundChange(); if (!m_hasForeground) - emit foregroundChanged(); + foregroundChange(); } void QQuickMaterialStyle::propagateTheme() @@ -516,6 +514,19 @@ void QQuickMaterialStyle::resetTheme() inheritTheme(material ? material->theme() : globalTheme); } +void QQuickMaterialStyle::themeChange() +{ + emit themeChanged(); + emit themeOrAccentChanged(); + emit primaryHighlightedTextColor(); + emit buttonColorChanged(); + emit buttonDisabledColorChanged(); + emit dialogColorChanged(); + emit tooltipColorChanged(); + emit toolBarColorChanged(); + emit toolTextColorChanged(); +} + QVariant QQuickMaterialStyle::primary() const { return primaryColor(); @@ -535,8 +546,7 @@ void QQuickMaterialStyle::setPrimary(const QVariant &var) m_customPrimary = custom; m_primary = primary; propagatePrimary(); - emit primaryChanged(); - emit paletteChanged(); + primaryChange(); } void QQuickMaterialStyle::inheritPrimary(uint primary, bool custom) @@ -547,8 +557,7 @@ void QQuickMaterialStyle::inheritPrimary(uint primary, bool custom) m_customPrimary = custom; m_primary = primary; propagatePrimary(); - emit primaryChanged(); - emit paletteChanged(); + primaryChange(); } void QQuickMaterialStyle::propagatePrimary() @@ -575,6 +584,13 @@ void QQuickMaterialStyle::resetPrimary() inheritPrimary(globalPrimary, false); } +void QQuickMaterialStyle::primaryChange() +{ + emit primaryChanged(); + emit toolBarColorChanged(); + emit toolTextColorChanged(); +} + QVariant QQuickMaterialStyle::accent() const { return accentColor(); @@ -594,8 +610,7 @@ void QQuickMaterialStyle::setAccent(const QVariant &var) m_customAccent = custom; m_accent = accent; propagateAccent(); - emit accentChanged(); - emit paletteChanged(); + accentChange(); } void QQuickMaterialStyle::inheritAccent(uint accent, bool custom) @@ -606,8 +621,7 @@ void QQuickMaterialStyle::inheritAccent(uint accent, bool custom) m_customAccent = custom; m_accent = accent; propagateAccent(); - emit accentChanged(); - emit paletteChanged(); + accentChange(); } void QQuickMaterialStyle::propagateAccent() @@ -634,6 +648,13 @@ void QQuickMaterialStyle::resetAccent() inheritAccent(globalAccent, false); } +void QQuickMaterialStyle::accentChange() +{ + emit accentChanged(); + emit themeOrAccentChanged(); + emit buttonColorChanged(); +} + QVariant QQuickMaterialStyle::foreground() const { if (!m_hasForeground) @@ -660,7 +681,7 @@ void QQuickMaterialStyle::setForeground(const QVariant &var) m_customForeground = custom; m_foreground = foreground; propagateForeground(); - emit foregroundChanged(); + foregroundChange(); } void QQuickMaterialStyle::inheritForeground(uint foreground, bool custom, bool has) @@ -672,7 +693,7 @@ void QQuickMaterialStyle::inheritForeground(uint foreground, bool custom, bool h m_customForeground = custom; m_foreground = foreground; propagateForeground(); - emit foregroundChanged(); + foregroundChange(); } void QQuickMaterialStyle::propagateForeground() @@ -697,6 +718,14 @@ void QQuickMaterialStyle::resetForeground() inheritForeground(material ? material->m_foreground : globalForeground, true, material ? material->m_hasForeground : false); } +void QQuickMaterialStyle::foregroundChange() +{ + emit foregroundChanged(); + emit primaryHighlightedTextColorChanged(); + // TODO: This causes a binding loop: see QTBUG-85699 and the comments on its fix +// emit toolTextColorChanged(); +} + QVariant QQuickMaterialStyle::background() const { return backgroundColor(); @@ -717,8 +746,7 @@ void QQuickMaterialStyle::setBackground(const QVariant &var) m_customBackground = custom; m_background = background; propagateBackground(); - emit backgroundChanged(); - emit paletteChanged(); + backgroundChange(); } void QQuickMaterialStyle::inheritBackground(uint background, bool custom, bool has) @@ -730,8 +758,7 @@ void QQuickMaterialStyle::inheritBackground(uint background, bool custom, bool h m_customBackground = custom; m_background = background; propagateBackground(); - emit backgroundChanged(); - emit paletteChanged(); + backgroundChange(); } void QQuickMaterialStyle::propagateBackground() @@ -756,6 +783,15 @@ void QQuickMaterialStyle::resetBackground() inheritBackground(material ? material->m_background : globalBackground, true, material ? material->m_hasBackground : false); } +void QQuickMaterialStyle::backgroundChange() +{ + emit backgroundChanged(); + emit buttonColorChanged(); + emit dialogColorChanged(); + emit tooltipColorChanged(); + emit toolBarColorChanged(); +} + int QQuickMaterialStyle::elevation() const { return m_elevation; @@ -767,7 +803,7 @@ void QQuickMaterialStyle::setElevation(int elevation) return; m_elevation = elevation; - emit elevationChanged(); + elevationChange(); } void QQuickMaterialStyle::resetElevation() @@ -775,6 +811,12 @@ void QQuickMaterialStyle::resetElevation() setElevation(0); } +void QQuickMaterialStyle::elevationChange() +{ + emit elevationChanged(); + emit buttonDisabledColorChanged(); +} + QColor QQuickMaterialStyle::primaryColor() const { if (m_customPrimary) diff --git a/src/imports/controls/material/qquickmaterialstyle_p.h b/src/imports/controls/material/qquickmaterialstyle_p.h index d2a89761..1207e9cc 100644 --- a/src/imports/controls/material/qquickmaterialstyle_p.h +++ b/src/imports/controls/material/qquickmaterialstyle_p.h @@ -66,38 +66,38 @@ class QQuickMaterialStyle : public QQuickAttachedObject Q_PROPERTY(QColor primaryColor READ primaryColor NOTIFY primaryChanged FINAL) // TODO: remove? Q_PROPERTY(QColor accentColor READ accentColor NOTIFY accentChanged FINAL) // TODO: remove? Q_PROPERTY(QColor backgroundColor READ backgroundColor NOTIFY backgroundChanged FINAL) - Q_PROPERTY(QColor primaryTextColor READ primaryTextColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor primaryHighlightedTextColor READ primaryHighlightedTextColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor secondaryTextColor READ secondaryTextColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor hintTextColor READ hintTextColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor textSelectionColor READ textSelectionColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor dropShadowColor READ dropShadowColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor dividerColor READ dividerColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor iconColor READ iconColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor iconDisabledColor READ iconDisabledColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor buttonColor READ buttonColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor buttonDisabledColor READ buttonDisabledColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor highlightedButtonColor READ highlightedButtonColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor frameColor READ frameColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor rippleColor READ rippleColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor highlightedRippleColor READ highlightedRippleColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor switchUncheckedTrackColor READ switchUncheckedTrackColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor switchCheckedTrackColor READ switchCheckedTrackColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor switchUncheckedHandleColor READ switchUncheckedHandleColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor switchCheckedHandleColor READ switchCheckedHandleColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor switchDisabledTrackColor READ switchDisabledTrackColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor switchDisabledHandleColor READ switchDisabledHandleColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor scrollBarColor READ scrollBarColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor scrollBarHoveredColor READ scrollBarHoveredColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor scrollBarPressedColor READ scrollBarPressedColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor dialogColor READ dialogColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor backgroundDimColor READ backgroundDimColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor listHighlightColor READ listHighlightColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor tooltipColor READ tooltipColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor toolBarColor READ toolBarColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor toolTextColor READ toolTextColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor spinBoxDisabledIconColor READ spinBoxDisabledIconColor NOTIFY paletteChanged FINAL) - Q_PROPERTY(QColor sliderDisabledColor READ sliderDisabledColor NOTIFY paletteChanged FINAL) + Q_PROPERTY(QColor primaryTextColor READ primaryTextColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor primaryHighlightedTextColor READ primaryHighlightedTextColor NOTIFY primaryHighlightedTextColorChanged FINAL) + Q_PROPERTY(QColor secondaryTextColor READ secondaryTextColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor hintTextColor READ hintTextColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor textSelectionColor READ textSelectionColor NOTIFY themeOrAccentChanged FINAL) + Q_PROPERTY(QColor dropShadowColor READ dropShadowColor CONSTANT FINAL) + Q_PROPERTY(QColor dividerColor READ dividerColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor iconColor READ iconColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor iconDisabledColor READ iconDisabledColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor buttonColor READ buttonColor NOTIFY buttonColorChanged FINAL) + Q_PROPERTY(QColor buttonDisabledColor READ buttonDisabledColor NOTIFY buttonDisabledColorChanged FINAL) + Q_PROPERTY(QColor highlightedButtonColor READ highlightedButtonColor NOTIFY buttonColorChanged FINAL) + Q_PROPERTY(QColor frameColor READ frameColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor rippleColor READ rippleColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor highlightedRippleColor READ highlightedRippleColor NOTIFY themeOrAccentChanged FINAL) + Q_PROPERTY(QColor switchUncheckedTrackColor READ switchUncheckedTrackColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor switchCheckedTrackColor READ switchCheckedTrackColor NOTIFY themeOrAccentChanged FINAL) + Q_PROPERTY(QColor switchUncheckedHandleColor READ switchUncheckedHandleColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor switchCheckedHandleColor READ switchCheckedHandleColor NOTIFY themeOrAccentChanged FINAL) + Q_PROPERTY(QColor switchDisabledTrackColor READ switchDisabledTrackColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor switchDisabledHandleColor READ switchDisabledHandleColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor scrollBarColor READ scrollBarColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor scrollBarHoveredColor READ scrollBarHoveredColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor scrollBarPressedColor READ scrollBarPressedColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor dialogColor READ dialogColor NOTIFY dialogColorChanged FINAL) + Q_PROPERTY(QColor backgroundDimColor READ backgroundDimColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor listHighlightColor READ listHighlightColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor tooltipColor READ tooltipColor NOTIFY tooltipColorChanged FINAL) + Q_PROPERTY(QColor toolBarColor READ toolBarColor NOTIFY toolBarColorChanged FINAL) + Q_PROPERTY(QColor toolTextColor READ toolTextColor NOTIFY toolTextColorChanged FINAL) + Q_PROPERTY(QColor spinBoxDisabledIconColor READ spinBoxDisabledIconColor NOTIFY themeChanged FINAL) + Q_PROPERTY(QColor sliderDisabledColor READ sliderDisabledColor NOTIFY themeChanged FINAL REVISION 15) Q_PROPERTY(int touchTarget READ touchTarget CONSTANT FINAL) Q_PROPERTY(int buttonHeight READ buttonHeight CONSTANT FINAL) @@ -174,34 +174,40 @@ public: void inheritTheme(Theme theme); void propagateTheme(); void resetTheme(); + void themeChange(); QVariant primary() const; void setPrimary(const QVariant &accent); void inheritPrimary(uint primary, bool custom); void propagatePrimary(); void resetPrimary(); + void primaryChange(); QVariant accent() const; void setAccent(const QVariant &accent); void inheritAccent(uint accent, bool custom); void propagateAccent(); void resetAccent(); + void accentChange(); QVariant foreground() const; void setForeground(const QVariant &foreground); void inheritForeground(uint foreground, bool custom, bool has); void propagateForeground(); void resetForeground(); + void foregroundChange(); QVariant background() const; void setBackground(const QVariant &background); void inheritBackground(uint background, bool custom, bool has); void propagateBackground(); void resetBackground(); + void backgroundChange(); int elevation() const; void setElevation(int elevation); void resetElevation(); + void elevationChange(); QColor primaryColor() const; QColor accentColor() const; @@ -265,7 +271,15 @@ Q_SIGNALS: void backgroundChanged(); void elevationChanged(); - void paletteChanged(); + void themeOrAccentChanged(); + + void primaryHighlightedTextColorChanged(); + void buttonColorChanged(); + void buttonDisabledColorChanged(); + void dialogColorChanged(); + void tooltipColorChanged(); + void toolBarColorChanged(); + void toolTextColorChanged(); protected: void attachedParentChange(QQuickAttachedObject *newParent, QQuickAttachedObject *oldParent) override; diff --git a/src/imports/controls/plugins.qmltypes b/src/imports/controls/plugins.qmltypes index c3e53431..e8212c55 100644 --- a/src/imports/controls/plugins.qmltypes +++ b/src/imports/controls/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.Controls 2.14' +// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.Controls 2.15' Module { dependencies: [ @@ -589,6 +589,14 @@ Module { defaultProperty: "contentData" } Component { + prototype: "QQuickHorizontalHeaderView" + name: "QtQuick.Controls/HorizontalHeaderView 2.15" + exports: ["QtQuick.Controls/HorizontalHeaderView 2.15"] + exportMetaObjectRevisions: [15] + isComposite: true + defaultProperty: "flickableData" + } + Component { prototype: "QQuickItemDelegate" name: "QtQuick.Controls/ItemDelegate 2.0" exports: ["QtQuick.Controls/ItemDelegate 2.0"] @@ -876,4 +884,12 @@ Module { isComposite: true defaultProperty: "data" } + Component { + prototype: "QQuickVerticalHeaderView" + name: "QtQuick.Controls/VerticalHeaderView 2.15" + exports: ["QtQuick.Controls/VerticalHeaderView 2.15"] + exportMetaObjectRevisions: [15] + isComposite: true + defaultProperty: "flickableData" + } } diff --git a/src/imports/controls/universal/ComboBox.qml b/src/imports/controls/universal/ComboBox.qml index fd2d8935..9b88ccf9 100644 --- a/src/imports/controls/universal/ComboBox.qml +++ b/src/imports/controls/universal/ComboBox.qml @@ -56,7 +56,7 @@ T.ComboBox { Universal.theme: editable && activeFocus ? Universal.Light : undefined delegate: ItemDelegate { - width: parent.width + width: ListView.view.width text: control.textRole ? (Array.isArray(control.model) ? modelData[control.textRole] : model[control.textRole]) : modelData font.weight: control.currentIndex === index ? Font.DemiBold : Font.Normal highlighted: control.highlightedIndex === index diff --git a/src/imports/controls/universal/DialogButtonBox.qml b/src/imports/controls/universal/DialogButtonBox.qml index 0458c39d..103b46c2 100644 --- a/src/imports/controls/universal/DialogButtonBox.qml +++ b/src/imports/controls/universal/DialogButtonBox.qml @@ -59,6 +59,7 @@ T.DialogButtonBox { } contentItem: ListView { + implicitWidth: contentWidth model: control.contentModel spacing: control.spacing orientation: ListView.Horizontal diff --git a/src/imports/controls/universal/plugins.qmltypes b/src/imports/controls/universal/plugins.qmltypes index 1734c01b..c38e39e1 100644 --- a/src/imports/controls/universal/plugins.qmltypes +++ b/src/imports/controls/universal/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.Controls.Universal 2.14' +// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.Controls.Universal 2.15' Module { dependencies: ["QtQuick.Controls 2.0"] diff --git a/src/imports/platform/platform.pro b/src/imports/platform/platform.pro index 043b0172..d9bcfcb8 100644 --- a/src/imports/platform/platform.pro +++ b/src/imports/platform/platform.pro @@ -1,9 +1,9 @@ TARGET = qtlabsplatformplugin TARGETPATH = Qt/labs/platform -IMPORT_VERSION = 1.0 +IMPORT_VERSION = 1.1 QT += qml quick -QT_PRIVATE += core-private gui-private qml-private quick-private +QT_PRIVATE += core-private gui-private qml-private quick-private quicktemplates2-private DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII diff --git a/src/imports/platform/plugins.qmltypes b/src/imports/platform/plugins.qmltypes index 7b165ef3..e9312047 100644 --- a/src/imports/platform/plugins.qmltypes +++ b/src/imports/platform/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable Qt.labs.platform 1.0' +// 'qmlplugindump -nonrelocatable Qt.labs.platform 1.1' Module { dependencies: ["QtQuick 2.0"] @@ -288,8 +288,11 @@ Module { Component { name: "QQuickPlatformMenuItem" prototype: "QObject" - exports: ["Qt.labs.platform/MenuItem 1.0"] - exportMetaObjectRevisions: [0] + exports: [ + "Qt.labs.platform/MenuItem 1.0", + "Qt.labs.platform/MenuItem 1.1" + ] + exportMetaObjectRevisions: [0, 1] Property { name: "menu"; type: "QQuickPlatformMenu"; isReadonly: true; isPointer: true } Property { name: "subMenu"; type: "QQuickPlatformMenu"; isReadonly: true; isPointer: true } Property { name: "group"; type: "QQuickPlatformMenuItemGroup"; isPointer: true } diff --git a/src/imports/platform/qquickplatformfiledialog.cpp b/src/imports/platform/qquickplatformfiledialog.cpp index 2ef08ef6..af5475fa 100644 --- a/src/imports/platform/qquickplatformfiledialog.cpp +++ b/src/imports/platform/qquickplatformfiledialog.cpp @@ -353,7 +353,6 @@ void QQuickPlatformFileDialog::resetNameFilters() } /*! - \qmlpropertygroup Qt.labs.platform::FileDialog::selectedNameFilter \qmlproperty int Qt.labs.platform::FileDialog::selectedNameFilter.index \qmlproperty string Qt.labs.platform::FileDialog::selectedNameFilter.name \qmlproperty list<string> Qt.labs.platform::FileDialog::selectedNameFilter.extensions @@ -553,8 +552,14 @@ QUrl QQuickPlatformFileDialog::addDefaultSuffix(const QUrl &file) const QUrl url = file; const QString path = url.path(); const QString suffix = m_options->defaultSuffix(); - if (!suffix.isEmpty() && !path.endsWith(QLatin1Char('/')) && path.lastIndexOf(QLatin1Char('.')) == -1) + // Urls with "content" scheme do not require suffixes. Such schemes are + // used on Android. + const bool isContentScheme = url.scheme() == QStringLiteral("content"); + if (!isContentScheme && !suffix.isEmpty() && !path.endsWith(QLatin1Char('/')) + && path.lastIndexOf(QLatin1Char('.')) == -1) { url.setPath(path + QLatin1Char('.') + suffix); + } + return url; } diff --git a/src/imports/platform/qquickplatformmenu.cpp b/src/imports/platform/qquickplatformmenu.cpp index 1f5f52d7..b5289f33 100644 --- a/src/imports/platform/qquickplatformmenu.cpp +++ b/src/imports/platform/qquickplatformmenu.cpp @@ -610,10 +610,9 @@ void QQuickPlatformMenu::setFont(const QFont& font) /*! \since Qt.labs.platform 1.1 (Qt 5.12) - \qmlpropertygroup Qt.labs.platform::MenuItem::icon - \qmlproperty url Qt.labs.platform::MenuItem::icon.source - \qmlproperty string Qt.labs.platform::MenuItem::icon.name - \qmlproperty bool Qt.labs.platform::MenuItem::icon.mask + \qmlproperty url Qt.labs.platform::Menu::icon.source + \qmlproperty string Qt.labs.platform::Menu::icon.name + \qmlproperty bool Qt.labs.platform::Menu::icon.mask This property holds the menu item's icon. */ diff --git a/src/imports/platform/qquickplatformmenubar.cpp b/src/imports/platform/qquickplatformmenubar.cpp index 99757829..f7199083 100644 --- a/src/imports/platform/qquickplatformmenubar.cpp +++ b/src/imports/platform/qquickplatformmenubar.cpp @@ -205,6 +205,7 @@ void QQuickPlatformMenuBar::insertMenu(int index, QQuickPlatformMenu *menu) menu->setMenuBar(this); if (m_handle) m_handle->insertMenu(menu->create(), before ? before->handle() : nullptr); + menu->sync(); emit menusChanged(); } diff --git a/src/imports/platform/qquickplatformmenuitem.cpp b/src/imports/platform/qquickplatformmenuitem.cpp index fa3fdafb..5a8b3798 100644 --- a/src/imports/platform/qquickplatformmenuitem.cpp +++ b/src/imports/platform/qquickplatformmenuitem.cpp @@ -43,6 +43,7 @@ #include <QtGui/qkeysequence.h> #include <QtGui/qpa/qplatformtheme.h> #include <QtGui/private/qguiapplication_p.h> +#include <QtQuickTemplates2/private/qquickshortcutcontext_p_p.h> #include "widgets/qwidgetplatform_p.h" @@ -120,6 +121,16 @@ QQuickPlatformMenuItem::~QQuickPlatformMenuItem() m_menu->removeItem(this); if (m_group) m_group->removeItem(this); +#if QT_CONFIG(shortcut) + if (m_shortcutId != -1) { + QKeySequence sequence; + if (m_shortcut.type() == QVariant::Int) + sequence = QKeySequence(static_cast<QKeySequence::StandardKey>(m_shortcut.toInt())); + else + sequence = QKeySequence::fromString(m_shortcut.toString()); + QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(m_shortcutId, this, sequence); + } +#endif delete m_iconLoader; m_iconLoader = nullptr; delete m_handle; @@ -165,8 +176,13 @@ void QQuickPlatformMenuItem::sync() m_handle->setText(m_text); m_handle->setFont(m_font); m_handle->setHasExclusiveGroup(m_group && m_group->isExclusive()); - if (m_subMenu && m_subMenu->handle()) - m_handle->setMenu(m_subMenu->handle()); + if (m_subMenu) { + // Sync first as dynamically created menus may need to get the + // handle recreated + m_subMenu->sync(); + if (m_subMenu->handle()) + m_handle->setMenu(m_subMenu->handle()); + } #if QT_CONFIG(shortcut) QKeySequence sequence; @@ -505,13 +521,50 @@ QVariant QQuickPlatformMenuItem::shortcut() const return m_shortcut; } +bool QQuickPlatformMenuItem::event(QEvent *e) +{ +#if QT_CONFIG(shortcut) + if (e->type() == QEvent::Shortcut) { + QShortcutEvent *se = static_cast<QShortcutEvent *>(e); + if (se->shortcutId() == m_shortcutId) { + activate(); + return true; + } + } +#endif + return QObject::event(e); +} + void QQuickPlatformMenuItem::setShortcut(const QVariant& shortcut) { if (m_shortcut == shortcut) return; +#if QT_CONFIG(shortcut) + if (m_shortcutId != -1) { + QKeySequence sequence; + if (m_shortcut.type() == QVariant::Int) + sequence = QKeySequence(static_cast<QKeySequence::StandardKey>(m_shortcut.toInt())); + else + sequence = QKeySequence::fromString(m_shortcut.toString()); + QGuiApplicationPrivate::instance()->shortcutMap.removeShortcut(m_shortcutId, this, sequence); + } +#endif m_shortcut = shortcut; sync(); +#if QT_CONFIG(shortcut) + QKeySequence sequence; + if (m_shortcut.type() == QVariant::Int) + sequence = QKeySequence(static_cast<QKeySequence::StandardKey>(m_shortcut.toInt())); + else + sequence = QKeySequence::fromString(m_shortcut.toString()); + if (!sequence.isEmpty()) { + m_shortcutId = QGuiApplicationPrivate::instance()->shortcutMap.addShortcut(this, sequence, + Qt::WindowShortcut, QQuickShortcutContext::matcher); + } else { + m_shortcutId = -1; + } +#endif emit shortcutChanged(); } @@ -539,7 +592,6 @@ void QQuickPlatformMenuItem::setFont(const QFont& font) /*! \since Qt.labs.platform 1.1 (Qt 5.12) - \qmlpropertygroup Qt.labs.platform::MenuItem::icon \qmlproperty url Qt.labs.platform::MenuItem::icon.source \qmlproperty string Qt.labs.platform::MenuItem::icon.name \qmlproperty bool Qt.labs.platform::MenuItem::icon.mask diff --git a/src/imports/platform/qquickplatformmenuitem_p.h b/src/imports/platform/qquickplatformmenuitem_p.h index f1143e64..e3d5258a 100644 --- a/src/imports/platform/qquickplatformmenuitem_p.h +++ b/src/imports/platform/qquickplatformmenuitem_p.h @@ -167,6 +167,7 @@ protected: QQuickPlatformIconLoader *iconLoader() const; + bool event(QEvent *e) override; private Q_SLOTS: void activate(); void updateIcon(); @@ -187,6 +188,7 @@ private: QQuickPlatformMenuItemGroup *m_group; mutable QQuickPlatformIconLoader *m_iconLoader; QPlatformMenuItem *m_handle; + int m_shortcutId = -1; friend class QQuickPlatformMenu; friend class QQuickPlatformMenuItemGroup; diff --git a/src/imports/platform/qquickplatformsystemtrayicon.cpp b/src/imports/platform/qquickplatformsystemtrayicon.cpp index da483822..442da037 100644 --- a/src/imports/platform/qquickplatformsystemtrayicon.cpp +++ b/src/imports/platform/qquickplatformsystemtrayicon.cpp @@ -356,7 +356,6 @@ QRect QQuickPlatformSystemTrayIcon::geometry() const /*! \since Qt.labs.platform 1.1 (Qt 5.12) - \qmlpropertygroup Qt.labs.platform::SystemTrayIcon::icon \qmlproperty url Qt.labs.platform::SystemTrayIcon::icon.source \qmlproperty string Qt.labs.platform::SystemTrayIcon::icon.name \qmlproperty bool Qt.labs.platform::SystemTrayIcon::icon.mask diff --git a/src/imports/platform/qtlabsplatformplugin.cpp b/src/imports/platform/qtlabsplatformplugin.cpp index 98d5dcc4..90bdb121 100644 --- a/src/imports/platform/qtlabsplatformplugin.cpp +++ b/src/imports/platform/qtlabsplatformplugin.cpp @@ -91,6 +91,7 @@ void QtLabsPlatformPlugin::registerTypes(const char *uri) qmlRegisterType<QQuickPlatformMenu>(uri, 1, 0, "Menu"); qmlRegisterType<QQuickPlatformMenuBar>(uri, 1, 0, "MenuBar"); qmlRegisterType<QQuickPlatformMenuItem>(uri, 1, 0, "MenuItem"); + qmlRegisterType<QQuickPlatformMenuItem, 1>(uri, 1, 1, "MenuItem"); qmlRegisterType<QQuickPlatformMenuItemGroup>(uri, 1, 0, "MenuItemGroup"); qmlRegisterType<QQuickPlatformMenuSeparator>(uri, 1, 0, "MenuSeparator"); qRegisterMetaType<QPlatformMenu::MenuType>(); diff --git a/src/imports/templates/plugins.qmltypes b/src/imports/templates/plugins.qmltypes index da81e095..42c04c80 100644 --- a/src/imports/templates/plugins.qmltypes +++ b/src/imports/templates/plugins.qmltypes @@ -4,7 +4,7 @@ import QtQuick.tooling 1.2 // It is used for QML tooling purposes only. // // This file was auto-generated by: -// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.Templates 2.14' +// 'qmlplugindump -nonrelocatable -dependencies dependencies.json QtQuick.Templates 2.15' Module { dependencies: ["QtQuick 2.9", "QtQuick.Window 2.2"] @@ -273,10 +273,11 @@ Module { "QtQuick.Templates/ComboBox 2.0", "QtQuick.Templates/ComboBox 2.1", "QtQuick.Templates/ComboBox 2.14", + "QtQuick.Templates/ComboBox 2.15", "QtQuick.Templates/ComboBox 2.2", "QtQuick.Templates/ComboBox 2.5" ] - exportMetaObjectRevisions: [0, 1, 14, 2, 5] + exportMetaObjectRevisions: [0, 1, 14, 15, 2, 5] Property { name: "count"; type: "int"; isReadonly: true } Property { name: "model"; type: "QVariant" } Property { name: "delegateModel"; type: "QQmlInstanceModel"; isReadonly: true; isPointer: true } @@ -301,6 +302,7 @@ Module { Property { name: "implicitIndicatorHeight"; revision: 5; type: "double"; isReadonly: true } Property { name: "currentValue"; revision: 14; type: "QVariant"; isReadonly: true } Property { name: "valueRole"; revision: 14; type: "string" } + Property { name: "selectTextByMouse"; revision: 15; type: "bool" } Signal { name: "activated" Parameter { name: "index"; type: "int" } @@ -322,6 +324,7 @@ Module { Signal { name: "implicitIndicatorHeightChanged"; revision: 5 } Signal { name: "valueRoleChanged"; revision: 14 } Signal { name: "currentValueChanged"; revision: 14 } + Signal { name: "selectTextByMouseChanged"; revision: 15 } Method { name: "incrementCurrentIndex" } Method { name: "decrementCurrentIndex" } Method { name: "selectAll"; revision: 2 } @@ -651,6 +654,20 @@ Module { Signal { name: "implicitLabelHeightChanged"; revision: 5 } } Component { + name: "QQuickHeaderViewBase" + defaultProperty: "flickableData" + prototype: "QQuickTableView" + Property { name: "textRole"; type: "string" } + } + Component { + name: "QQuickHorizontalHeaderView" + defaultProperty: "flickableData" + prototype: "QQuickHeaderViewBase" + exports: ["QtQuick.Templates/HorizontalHeaderView 2.15"] + exportMetaObjectRevisions: [0] + attachedType: "QQuickTableViewAttached" + } + Component { name: "QQuickIcon" Property { name: "name"; type: "string" } Property { name: "source"; type: "QUrl" } @@ -1265,7 +1282,6 @@ Module { prototype: "QObject" Property { name: "centerIn"; type: "QQuickItem"; isPointer: true } } - Component { name: "QQuickPopupItem"; defaultProperty: "contentData"; prototype: "QQuickPage" } Component { name: "QQuickProgressBar" defaultProperty: "data" @@ -1355,19 +1371,6 @@ Module { Method { name: "decrease" } } Component { - name: "QQuickRootItem" - defaultProperty: "data" - prototype: "QQuickItem" - Method { - name: "setWidth" - Parameter { name: "w"; type: "int" } - } - Method { - name: "setHeight" - Parameter { name: "h"; type: "int" } - } - } - Component { name: "QQuickRoundButton" defaultProperty: "data" prototype: "QQuickButton" @@ -1852,6 +1855,37 @@ Module { exportMetaObjectRevisions: [0] } Component { + name: "QQuickTableView" + defaultProperty: "flickableData" + prototype: "QQuickFlickable" + exports: ["QtQuick.Templates/__TableView__ 2.15"] + exportMetaObjectRevisions: [15] + attachedType: "QQuickTableViewAttached" + Property { name: "rows"; type: "int"; isReadonly: true } + Property { name: "columns"; type: "int"; isReadonly: true } + Property { name: "rowSpacing"; type: "double" } + Property { name: "columnSpacing"; type: "double" } + Property { name: "rowHeightProvider"; type: "QJSValue" } + Property { name: "columnWidthProvider"; type: "QJSValue" } + Property { name: "model"; type: "QVariant" } + Property { name: "delegate"; type: "QQmlComponent"; isPointer: true } + Property { name: "reuseItems"; type: "bool" } + Property { name: "contentWidth"; type: "double" } + Property { name: "contentHeight"; type: "double" } + Property { name: "syncView"; revision: 14; type: "QQuickTableView"; isPointer: true } + Property { name: "syncDirection"; revision: 14; type: "Qt::Orientations" } + Signal { name: "syncViewChanged"; revision: 14 } + Signal { name: "syncDirectionChanged"; revision: 14 } + Method { name: "forceLayout" } + } + Component { + name: "QQuickTableViewAttached" + prototype: "QObject" + Property { name: "view"; type: "QQuickTableView"; isReadonly: true; isPointer: true } + Signal { name: "pooled" } + Signal { name: "reused" } + } + Component { name: "QQuickText" defaultProperty: "data" prototype: "QQuickImplicitSizeItem" @@ -2794,6 +2828,14 @@ Module { Property { name: "displacement"; type: "double"; isReadonly: true } } Component { + name: "QQuickVerticalHeaderView" + defaultProperty: "flickableData" + prototype: "QQuickHeaderViewBase" + exports: ["QtQuick.Templates/VerticalHeaderView 2.15"] + exportMetaObjectRevisions: [0] + attachedType: "QQuickTableViewAttached" + } + Component { name: "QQuickWindow" defaultProperty: "data" prototype: "QWindow" @@ -3018,6 +3060,12 @@ Module { Method { name: "raise" } Method { name: "lower" } Method { + name: "startSystemResize" + type: "bool" + Parameter { name: "edges"; type: "Qt::Edges" } + } + Method { name: "startSystemMove"; type: "bool" } + Method { name: "setTitle" Parameter { type: "string" } } diff --git a/src/imports/templates/qmldir b/src/imports/templates/qmldir index afb94818..9f3773a8 100644 --- a/src/imports/templates/qmldir +++ b/src/imports/templates/qmldir @@ -2,3 +2,4 @@ module QtQuick.Templates plugin qtquicktemplates2plugin classname QtQuickTemplates2Plugin depends QtQuick.Window 2.2 +depends QtQuick 2.9 diff --git a/src/imports/templates/qtquicktemplates2plugin.cpp b/src/imports/templates/qtquicktemplates2plugin.cpp index 3b085c56..cee8e53d 100644 --- a/src/imports/templates/qtquicktemplates2plugin.cpp +++ b/src/imports/templates/qtquicktemplates2plugin.cpp @@ -142,6 +142,8 @@ private: QtQuickTemplates2Plugin::QtQuickTemplates2Plugin(QObject *parent) : QQmlExtensionPlugin(parent), registered(false) { + volatile auto initialization = &QQuickTemplates_initializeModule; + Q_UNUSED(initialization) #if QT_CONFIG(shortcut) originalContextMatcher = qt_quick_shortcut_context_matcher(); qt_quick_set_shortcut_context_matcher(QQuickShortcutContext::matcher); diff --git a/src/quickcontrols2/qquickiconimage.cpp b/src/quickcontrols2/qquickiconimage.cpp index d86afd7f..11bb3bca 100644 --- a/src/quickcontrols2/qquickiconimage.cpp +++ b/src/quickcontrols2/qquickiconimage.cpp @@ -42,6 +42,12 @@ QT_BEGIN_NAMESPACE +QQuickIconImagePrivate::~QQuickIconImagePrivate() +{ + qDeleteAll(icon.entries); + icon.entries.clear(); +} + bool QQuickIconImagePrivate::updateDevicePixelRatio(qreal targetDevicePixelRatio) { if (isThemeIcon) { @@ -132,6 +138,7 @@ void QQuickIconImage::setName(const QString &name) if (d->icon.iconName == name) return; + qDeleteAll(d->icon.entries); d->icon = QIconLoader::instance()->loadIcon(name); if (isComponentComplete()) d->updateIcon(); diff --git a/src/quickcontrols2/qquickiconimage_p_p.h b/src/quickcontrols2/qquickiconimage_p_p.h index 0c755ff6..11bf5e92 100644 --- a/src/quickcontrols2/qquickiconimage_p_p.h +++ b/src/quickcontrols2/qquickiconimage_p_p.h @@ -59,6 +59,7 @@ class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickIconImagePrivate : public QQuickImag Q_DECLARE_PUBLIC(QQuickIconImage) public: + ~QQuickIconImagePrivate() override; void updateIcon(); void updateFillMode(); qreal calculateDevicePixelRatio() const; diff --git a/src/quicktemplates2/accessible/accessible.pri b/src/quicktemplates2/accessible/accessible.pri new file mode 100644 index 00000000..93660b9f --- /dev/null +++ b/src/quicktemplates2/accessible/accessible.pri @@ -0,0 +1,5 @@ +HEADERS += \ + $$PWD/qaccessiblequickpage_p.h + +SOURCES += \ + $$PWD/qaccessiblequickpage.cpp diff --git a/src/quicktemplates2/accessible/qaccessiblequickpage.cpp b/src/quicktemplates2/accessible/qaccessiblequickpage.cpp new file mode 100644 index 00000000..90ac49f9 --- /dev/null +++ b/src/quicktemplates2/accessible/qaccessiblequickpage.cpp @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Templates 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 "qaccessiblequickpage_p.h" +#include "qquickpage_p.h" + +QT_BEGIN_NAMESPACE + +QAccessibleQuickPage::QAccessibleQuickPage(QQuickPage *page) + : QAccessibleQuickItem(page) +{ +} + +QAccessibleInterface *QAccessibleQuickPage::child(int index) const +{ + const QList<QQuickItem*> kids = orderedChildItems(); + if (QQuickItem *item = kids.value(index)) + return QAccessible::queryAccessibleInterface(item); + return nullptr; +} + +int QAccessibleQuickPage::indexOfChild(const QAccessibleInterface *iface) const +{ + const QList<QQuickItem*> kids = orderedChildItems(); + return (int)kids.indexOf(static_cast<QQuickItem*>(iface->object())); +} + +QList<QQuickItem *> QAccessibleQuickPage::orderedChildItems() const +{ + // Just ensures that the header is first, and footer is last. Other existing order is kept. + const QQuickPage *p = page(); + QList<QQuickItem*> kids = childItems(); + const qsizetype hidx = kids.indexOf(p->header()); + if (hidx != -1) + kids.move(hidx, 0); + const qsizetype fidx = kids.indexOf(p->footer()); + if (fidx != -1) + kids.move(fidx, kids.count() - 1); + return kids; +} + +QQuickPage *QAccessibleQuickPage::page() const +{ + return static_cast<QQuickPage*>(object()); +} + +QT_END_NAMESPACE + diff --git a/src/quicktemplates2/accessible/qaccessiblequickpage_p.h b/src/quicktemplates2/accessible/qaccessiblequickpage_p.h new file mode 100644 index 00000000..9b208c14 --- /dev/null +++ b/src/quicktemplates2/accessible/qaccessiblequickpage_p.h @@ -0,0 +1,70 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ +** +** This file is part of the Qt Quick Templates 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$ +** +****************************************************************************/ + +#ifndef QACCESSIBLEQUICKPAGE_H +#define QACCESSIBLEQUICKPAGE_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <QtQuick/private/qaccessiblequickitem_p.h> + +QT_BEGIN_NAMESPACE + +class QQuickPage; + +class QAccessibleQuickPage : public QAccessibleQuickItem +{ +public: + QAccessibleQuickPage(QQuickPage *page); + QAccessibleInterface *child(int index) const override; + int indexOfChild(const QAccessibleInterface *iface) const override; +private: + QQuickPage *page() const; + QList<QQuickItem *> orderedChildItems() const; +}; + +QT_END_NAMESPACE + +#endif // QACCESSIBLEQUICKPAGE_H diff --git a/src/quicktemplates2/qquickabstractbutton.cpp b/src/quicktemplates2/qquickabstractbutton.cpp index 8632e14c..20cf59c1 100644 --- a/src/quicktemplates2/qquickabstractbutton.cpp +++ b/src/quicktemplates2/qquickabstractbutton.cpp @@ -215,8 +215,20 @@ bool QQuickAbstractButtonPrivate::acceptKeyClick(Qt::Key key) const bool QQuickAbstractButtonPrivate::isPressAndHoldConnected() { Q_Q(QQuickAbstractButton); - const auto signal = &QQuickAbstractButton::pressAndHold; - const QMetaMethod method = QMetaMethod::fromSignal(signal); + static const QMetaMethod method = [&]() { + const auto signal = &QQuickAbstractButton::pressAndHold; + return QMetaMethod::fromSignal(signal); + }(); + return q->isSignalConnected(method); +} + +bool QQuickAbstractButtonPrivate::isDoubleClickConnected() +{ + Q_Q(QQuickAbstractButton); + static const QMetaMethod method = [&]() { + const auto signal = &QQuickAbstractButton::doubleClicked; + return QMetaMethod::fromSignal(signal); + }(); return q->isSignalConnected(method); } @@ -387,6 +399,17 @@ void QQuickAbstractButtonPrivate::itemImplicitHeightChanged(QQuickItem *item) emit q->implicitIndicatorHeightChanged(); } +void QQuickAbstractButtonPrivate::itemDestroyed(QQuickItem *item) +{ + Q_Q(QQuickAbstractButton); + QQuickControlPrivate::itemDestroyed(item); + if (item == indicator) { + indicator = nullptr; + emit q->implicitIndicatorWidthChanged(); + emit q->implicitIndicatorHeightChanged(); + } +} + QQuickAbstractButton *QQuickAbstractButtonPrivate::findCheckedButton() const { Q_Q(const QQuickAbstractButton); @@ -438,6 +461,7 @@ QQuickAbstractButton::QQuickAbstractButton(QQuickItem *parent) setActiveFocusOnTab(true); setFocusPolicy(Qt::StrongFocus); setAcceptedMouseButtons(Qt::LeftButton); + setAcceptTouchEvents(true); #if QT_CONFIG(cursor) setCursor(Qt::ArrowCursor); #endif @@ -449,6 +473,7 @@ QQuickAbstractButton::QQuickAbstractButton(QQuickAbstractButtonPrivate &dd, QQui setActiveFocusOnTab(true); setFocusPolicy(Qt::StrongFocus); setAcceptedMouseButtons(Qt::LeftButton); + setAcceptTouchEvents(true); #if QT_CONFIG(cursor) setCursor(Qt::ArrowCursor); #endif @@ -734,12 +759,12 @@ void QQuickAbstractButton::setIndicator(QQuickItem *indicator) } /*! - \qmlpropertygroup QtQuick.Controls::AbstractButton::icon \qmlproperty string QtQuick.Controls::AbstractButton::icon.name \qmlproperty url QtQuick.Controls::AbstractButton::icon.source \qmlproperty int QtQuick.Controls::AbstractButton::icon.width \qmlproperty int QtQuick.Controls::AbstractButton::icon.height \qmlproperty color QtQuick.Controls::AbstractButton::icon.color + \qmlproperty bool QtQuick.Controls::AbstractButton::icon.cache This property group was added in QtQuick.Controls 2.3. @@ -1061,7 +1086,7 @@ void QQuickAbstractButton::keyReleaseEvent(QKeyEvent *event) { Q_D(QQuickAbstractButton); QQuickControl::keyReleaseEvent(event); - if (d->acceptKeyClick(static_cast<Qt::Key>(event->key()))) { + if (d->pressed && d->acceptKeyClick(static_cast<Qt::Key>(event->key()))) { setPressed(false); nextCheckState(); @@ -1084,9 +1109,11 @@ void QQuickAbstractButton::mousePressEvent(QMouseEvent *event) void QQuickAbstractButton::mouseDoubleClickEvent(QMouseEvent *event) { Q_D(QQuickAbstractButton); - QQuickControl::mouseDoubleClickEvent(event); - emit doubleClicked(); - d->wasDoubleClick = true; + if (d->isDoubleClickConnected()) { + QQuickControl::mouseDoubleClickEvent(event); + emit doubleClicked(); + d->wasDoubleClick = true; + } } void QQuickAbstractButton::timerEvent(QTimerEvent *event) diff --git a/src/quicktemplates2/qquickabstractbutton_p_p.h b/src/quicktemplates2/qquickabstractbutton_p_p.h index 9291c1a8..907790dc 100644 --- a/src/quicktemplates2/qquickabstractbutton_p_p.h +++ b/src/quicktemplates2/qquickabstractbutton_p_p.h @@ -80,6 +80,7 @@ public: virtual bool acceptKeyClick(Qt::Key key) const; bool isPressAndHoldConnected(); + bool isDoubleClickConnected(); void startPressAndHold(); void stopPressAndHold(); @@ -109,6 +110,7 @@ public: void itemImplicitWidthChanged(QQuickItem *item) override; void itemImplicitHeightChanged(QQuickItem *item) override; + void itemDestroyed(QQuickItem *item) override; // copied from qabstractbutton.cpp static const int AUTO_REPEAT_DELAY = 300; diff --git a/src/quicktemplates2/qquickaction.cpp b/src/quicktemplates2/qquickaction.cpp index 0b083339..8610cdfa 100644 --- a/src/quicktemplates2/qquickaction.cpp +++ b/src/quicktemplates2/qquickaction.cpp @@ -145,7 +145,7 @@ int QQuickActionPrivate::ShortcutEntry::shortcutId() const void QQuickActionPrivate::ShortcutEntry::grab(const QKeySequence &shortcut, bool enabled) { - if (shortcut.isEmpty()) + if (shortcut.isEmpty() || m_shortcutId) return; Qt::ShortcutContext context = Qt::WindowShortcut; // TODO @@ -381,12 +381,12 @@ void QQuickAction::setText(const QString &text) } /*! - \qmlpropertygroup QtQuick.Controls::Action::icon \qmlproperty string QtQuick.Controls::Action::icon.name \qmlproperty url QtQuick.Controls::Action::icon.source \qmlproperty int QtQuick.Controls::Action::icon.width \qmlproperty int QtQuick.Controls::Action::icon.height \qmlproperty color QtQuick.Controls::Action::icon.color + \qmlproperty bool QtQuick.Controls::Action::icon.cache \include qquickicon.qdocinc grouped-properties */ diff --git a/src/quicktemplates2/qquickapplicationwindow.cpp b/src/quicktemplates2/qquickapplicationwindow.cpp index 903de676..a9a4ad72 100644 --- a/src/quicktemplates2/qquickapplicationwindow.cpp +++ b/src/quicktemplates2/qquickapplicationwindow.cpp @@ -48,6 +48,7 @@ #include "qquickdeferredpointer_p_p.h" #include <QtCore/private/qobject_p.h> +#include <QtCore/qscopedvaluerollback.h> #include <QtQuick/private/qquickitem_p.h> #include <QtQuick/private/qquickitemchangelistener_p.h> @@ -174,6 +175,7 @@ public: QPalette palette; QQuickItem *activeFocusControl = nullptr; QQuickApplicationWindow *q_ptr = nullptr; + bool insideRelayout = false; }; static void layoutItem(QQuickItem *item, qreal y, qreal width) @@ -192,9 +194,10 @@ static void layoutItem(QQuickItem *item, qreal y, qreal width) void QQuickApplicationWindowPrivate::relayout() { Q_Q(QQuickApplicationWindow); - if (!complete) + if (!complete || insideRelayout) return; + QScopedValueRollback<bool> guard(insideRelayout, true); QQuickItem *content = q->contentItem(); qreal hh = header && header->isVisible() ? header->height() : 0; qreal fh = footer && footer->isVisible() ? footer->height() : 0; @@ -650,6 +653,8 @@ QQuickOverlay *QQuickApplicationWindow::overlay() const if (!d->overlay) { d->overlay = new QQuickOverlay(QQuickWindow::contentItem()); + // make the overlay discoverable by the virtual keyboard + d->q_ptr->setProperty("_q_QQuickOverlay", QVariant::fromValue<QQuickItem*>(d->overlay)); d->overlay->stackAfter(QQuickApplicationWindow::contentItem()); } return d->overlay; diff --git a/src/quicktemplates2/qquickcombobox.cpp b/src/quicktemplates2/qquickcombobox.cpp index d9bbd2bd..e7d99a5d 100644 --- a/src/quicktemplates2/qquickcombobox.cpp +++ b/src/quicktemplates2/qquickcombobox.cpp @@ -234,6 +234,7 @@ public: void updateCurrentText(); void updateCurrentValue(); void updateCurrentTextAndValue(); + void updateAcceptableInput(); bool isValidIndex(int index) const; @@ -265,6 +266,8 @@ public: void itemImplicitWidthChanged(QQuickItem *item) override; void itemImplicitHeightChanged(QQuickItem *item) override; + void setInputMethodHints(Qt::InputMethodHints hints, bool force = false); + static void hideOldPopup(QQuickPopup *popup); bool flat = false; @@ -288,6 +291,7 @@ public: QQmlComponent *delegate = nullptr; QQuickDeferredPointer<QQuickItem> indicator; QQuickDeferredPointer<QQuickPopup> popup; + bool m_acceptableInput = true; struct ExtraData { bool editable = false; @@ -404,13 +408,13 @@ void QQuickComboBoxPrivate::createdItem(int index, QObject *object) } if (index == currentIndex && !q->isEditable()) - updateCurrentText(); + updateCurrentTextAndValue(); } void QQuickComboBoxPrivate::modelUpdated() { if (!extra.isAllocated() || !extra->accepting) - updateCurrentText(); + updateCurrentTextAndValue(); } void QQuickComboBoxPrivate::countChanged() @@ -476,6 +480,26 @@ void QQuickComboBoxPrivate::updateCurrentTextAndValue() updateCurrentValue(); } +void QQuickComboBoxPrivate::updateAcceptableInput() +{ + Q_Q(QQuickComboBox); + + if (!contentItem) + return; + + const QQuickTextInput *textInputContentItem = qobject_cast<QQuickTextInput *>(contentItem); + + if (!textInputContentItem) + return; + + const bool newValue = textInputContentItem->hasAcceptableInput(); + + if (m_acceptableInput != newValue) { + m_acceptableInput = newValue; + emit q->acceptableInputChanged(); + } +} + bool QQuickComboBoxPrivate::isValidIndex(int index) const { return delegateModel && index >= 0 && index < delegateModel->count(); @@ -770,6 +794,16 @@ void QQuickComboBoxPrivate::itemImplicitWidthChanged(QQuickItem *item) emit q->implicitIndicatorWidthChanged(); } +void QQuickComboBoxPrivate::setInputMethodHints(Qt::InputMethodHints hints, bool force) +{ + Q_Q(QQuickComboBox); + if (!force && hints == q->inputMethodHints()) + return; + + extra.value().inputMethodHints = hints; + emit q->inputMethodHintsChanged(); +} + void QQuickComboBoxPrivate::itemImplicitHeightChanged(QQuickItem *item) { Q_Q(QQuickComboBox); @@ -787,10 +821,12 @@ void QQuickComboBoxPrivate::hideOldPopup(QQuickPopup *popup) popup->setVisible(false); popup->setParentItem(nullptr); +#if QT_CONFIG(accessibility) // Remove the item from the accessibility tree. QQuickAccessibleAttached *accessible = accessibleAttached(popup); if (accessible) accessible->setIgnored(true); +#endif } QQuickComboBox::QQuickComboBox(QQuickItem *parent) @@ -802,7 +838,8 @@ QQuickComboBox::QQuickComboBox(QQuickItem *parent) #if QT_CONFIG(cursor) setCursor(Qt::ArrowCursor); #endif - setInputMethodHints(Qt::ImhNoPredictiveText); + Q_D(QQuickComboBox); + d->setInputMethodHints(Qt::ImhNoPredictiveText, true); } QQuickComboBox::~QQuickComboBox() @@ -866,11 +903,11 @@ void QQuickComboBox::setModel(const QVariant& m) if (QAbstractItemModel* aim = qvariant_cast<QAbstractItemModel *>(d->model)) { QObjectPrivate::disconnect(aim, &QAbstractItemModel::dataChanged, - d, QOverload<>::of(&QQuickComboBoxPrivate::updateCurrentText)); + d, QOverload<>::of(&QQuickComboBoxPrivate::updateCurrentTextAndValue)); } if (QAbstractItemModel* aim = qvariant_cast<QAbstractItemModel *>(model)) { QObjectPrivate::connect(aim, &QAbstractItemModel::dataChanged, - d, QOverload<>::of(&QQuickComboBoxPrivate::updateCurrentText)); + d, QOverload<>::of(&QQuickComboBoxPrivate::updateCurrentTextAndValue)); } d->model = model; @@ -878,7 +915,7 @@ void QQuickComboBox::setModel(const QVariant& m) emit countChanged(); if (isComponentComplete()) { setCurrentIndex(count() > 0 ? 0 : -1); - d->updateCurrentText(); + d->updateCurrentTextAndValue(); } emit modelChanged(); } @@ -1435,11 +1472,7 @@ Qt::InputMethodHints QQuickComboBox::inputMethodHints() const void QQuickComboBox::setInputMethodHints(Qt::InputMethodHints hints) { Q_D(QQuickComboBox); - if (hints == inputMethodHints()) - return; - - d->extra.value().inputMethodHints = hints; - emit inputMethodHintsChanged(); + d->setInputMethodHints(hints); } /*! @@ -1474,7 +1507,7 @@ bool QQuickComboBox::isInputMethodComposing() const bool QQuickComboBox::hasAcceptableInput() const { Q_D(const QQuickComboBox); - return d->contentItem && d->contentItem->property("acceptableInput").toBool(); + return d->m_acceptableInput; } /*! @@ -1729,7 +1762,11 @@ void QQuickComboBox::focusInEvent(QFocusEvent *event) { Q_D(QQuickComboBox); QQuickControl::focusInEvent(event); - if (d->contentItem && isEditable()) + // Setting focus on TextField should not be done when drop down indicator was clicked + // That is why, if focus is not set with key reason, it should not be passed to textEdit by default. + // Focus on Edit Text should be set only intentionally by user. + if ((event->reason() == Qt::TabFocusReason || event->reason() == Qt::BacktabFocusReason || + event->reason() == Qt::ShortcutFocusReason) && d->contentItem && isEditable()) d->contentItem->forceActiveFocus(event->reason()); } @@ -1869,7 +1906,7 @@ bool QQuickComboBox::event(QEvent *e) { Q_D(QQuickComboBox); if (e->type() == QEvent::LanguageChange) - d->updateCurrentText(); + d->updateCurrentTextAndValue(); return QQuickControl::event(e); } @@ -1911,7 +1948,7 @@ void QQuickComboBox::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) QObjectPrivate::disconnect(oldInput, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput); QObjectPrivate::disconnect(oldInput, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText); disconnect(oldInput, &QQuickTextInput::inputMethodComposingChanged, this, &QQuickComboBox::inputMethodComposingChanged); - disconnect(oldInput, &QQuickTextInput::acceptableInputChanged, this, &QQuickComboBox::acceptableInputChanged); + QObjectPrivate::disconnect(oldInput, &QQuickTextInput::acceptableInputChanged, d, &QQuickComboBoxPrivate::updateAcceptableInput); } } if (newItem && isEditable()) { @@ -1920,12 +1957,14 @@ void QQuickComboBox::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) QObjectPrivate::connect(newInput, &QQuickTextInput::accepted, d, &QQuickComboBoxPrivate::acceptInput); QObjectPrivate::connect(newInput, &QQuickTextInput::textChanged, d, &QQuickComboBoxPrivate::updateEditText); connect(newInput, &QQuickTextInput::inputMethodComposingChanged, this, &QQuickComboBox::inputMethodComposingChanged); - connect(newInput, &QQuickTextInput::acceptableInputChanged, this, &QQuickComboBox::acceptableInputChanged); + QObjectPrivate::connect(newInput, &QQuickTextInput::acceptableInputChanged, d, &QQuickComboBoxPrivate::updateAcceptableInput); } #if QT_CONFIG(cursor) newItem->setCursor(Qt::IBeamCursor); #endif } + + d->updateAcceptableInput(); } void QQuickComboBox::localeChange(const QLocale &newLocale, const QLocale &oldLocale) diff --git a/src/quicktemplates2/qquickcontrol.cpp b/src/quicktemplates2/qquickcontrol.cpp index 4eb411c2..a719efd3 100644 --- a/src/quicktemplates2/qquickcontrol.cpp +++ b/src/quicktemplates2/qquickcontrol.cpp @@ -158,9 +158,6 @@ QQuickControlPrivate::QQuickControlPrivate() QQuickControlPrivate::~QQuickControlPrivate() { -#if QT_CONFIG(accessibility) - QAccessible::removeActivationObserver(this); -#endif } void QQuickControlPrivate::init() @@ -180,11 +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 && - point.pos() == previousPressPos) { - return true; + // 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); + 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; } @@ -848,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) @@ -858,10 +870,35 @@ void QQuickControlPrivate::hideOldItem(QQuickItem *item) item->setVisible(false); item->setParentItem(nullptr); +#if QT_CONFIG(accessibility) // Remove the item from the accessibility tree. QQuickAccessibleAttached *accessible = accessibleAttached(item); if (accessible) accessible->setIgnored(true); +#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() @@ -966,6 +1003,9 @@ QQuickControl::~QQuickControl() Q_D(QQuickControl); d->removeImplicitSizeListener(d->background, QQuickControlPrivate::ImplicitSizeChanges | QQuickItemPrivate::Geometry); d->removeImplicitSizeListener(d->contentItem); +#if QT_CONFIG(accessibility) + QAccessible::removeActivationObserver(d); +#endif } void QQuickControl::itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) diff --git a/src/quicktemplates2/qquickcontrol_p_p.h b/src/quicktemplates2/qquickcontrol_p_p.h index fa06c97f..a6e624c9 100644 --- a/src/quicktemplates2/qquickcontrol_p_p.h +++ b/src/quicktemplates2/qquickcontrol_p_p.h @@ -122,7 +122,7 @@ public: void setRightInset(qreal value, bool reset = false); void setBottomInset(qreal value, bool reset = false); - void resizeBackground(); + virtual void resizeBackground(); virtual void resizeContent(); virtual QQuickItem *getContentItem(); @@ -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/qquickdial.cpp b/src/quicktemplates2/qquickdial.cpp index 99bd0e98..906f952a 100644 --- a/src/quicktemplates2/qquickdial.cpp +++ b/src/quicktemplates2/qquickdial.cpp @@ -41,6 +41,8 @@ #include <QtQuick/private/qquickflickable_p.h> #include <QtQuickTemplates2/private/qquickcontrol_p_p.h> +#include <cmath> + QT_BEGIN_NAMESPACE /*! @@ -116,25 +118,37 @@ public: void cancelHandle(); void executeHandle(bool complete = false); + void updateAllValuesAreInteger(); + qreal from = 0; qreal to = 1; qreal value = 0; qreal position = 0; qreal angle = startAngle; qreal stepSize = 0; - bool pressed = false; QPointF pressPoint; qreal positionBeforePress = 0; QQuickDial::SnapMode snapMode = QQuickDial::NoSnap; QQuickDial::InputMode inputMode = QQuickDial::Circular; + QQuickDeferredPointer<QQuickItem> handle; bool wrap = false; bool live = true; - QQuickDeferredPointer<QQuickItem> handle; + bool pressed = false; + bool allValuesAreInteger = false; }; qreal QQuickDialPrivate::valueAt(qreal position) const { - return from + (to - from) * position; + qreal value = from + (to - from) * position; + + /* play nice with users expecting that integer from, to and stepSize leads to + integer values - given that we are using floating point internally (and in + the API of value), this does not hold, but it is easy enough to handle + */ + if (allValuesAreInteger) + value = qRound(value); + + return value; } qreal QQuickDialPrivate::snapPosition(qreal position) const @@ -308,11 +322,24 @@ void QQuickDialPrivate::executeHandle(bool complete) quickCompleteDeferred(q, handleName(), handle); } +static bool areRepresentableAsInteger(qreal num1, qreal num2, qreal num3) { + auto check = [](qreal number) -> bool { return std::nearbyint(number) == number; }; + return check(num1) && check(num2) && check(num3); +} + +void QQuickDialPrivate::updateAllValuesAreInteger() +{ + allValuesAreInteger = areRepresentableAsInteger(to, from, stepSize) && stepSize != 0.0; +} + QQuickDial::QQuickDial(QQuickItem *parent) : QQuickControl(*(new QQuickDialPrivate), parent) { setActiveFocusOnTab(true); setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(quicktemplates2_multitouch) + setAcceptTouchEvents(true); +#endif #if QT_CONFIG(cursor) setCursor(Qt::ArrowCursor); #endif @@ -339,6 +366,7 @@ void QQuickDial::setFrom(qreal from) d->from = from; emit fromChanged(); + d->updateAllValuesAreInteger(); if (isComponentComplete()) { setValue(d->value); d->updatePosition(); @@ -366,6 +394,7 @@ void QQuickDial::setTo(qreal to) return; d->to = to; + d->updateAllValuesAreInteger(); emit toChanged(); if (isComponentComplete()) { setValue(d->value); @@ -465,6 +494,7 @@ void QQuickDial::setStepSize(qreal step) return; d->stepSize = step; + d->updateAllValuesAreInteger(); emit stepSizeChanged(); } diff --git a/src/quicktemplates2/qquickdialogbuttonbox.cpp b/src/quicktemplates2/qquickdialogbuttonbox.cpp index f3dd2da1..e6db14eb 100644 --- a/src/quicktemplates2/qquickdialogbuttonbox.cpp +++ b/src/quicktemplates2/qquickdialogbuttonbox.cpp @@ -706,34 +706,19 @@ void QQuickDialogButtonBox::updatePolish() d->updateLayout(); } -class LanguageEventFilter : public QObject +bool QQuickDialogButtonBox::event(QEvent *e) { -public: - LanguageEventFilter(QQuickDialogButtonBoxPrivate *box) - : QObject(box->q_ptr) - , boxPrivate(box) - { - } - -protected: - bool eventFilter(QObject *, QEvent *event) - { - if (event->type() == QEvent::LanguageChange) - boxPrivate->updateLanguage(); - return false; - } - -private: - QQuickDialogButtonBoxPrivate *boxPrivate; -}; + Q_D(QQuickDialogButtonBox); + if (e->type() == QEvent::LanguageChange) + d->updateLanguage(); + return QQuickContainer::event(e); +} void QQuickDialogButtonBox::componentComplete() { Q_D(QQuickDialogButtonBox); QQuickContainer::componentComplete(); d->updateLayout(); - // TODO: use the solution in QTBUG-78141 instead, when it's implemented. - qApp->installEventFilter(new LanguageEventFilter(d)); } void QQuickDialogButtonBox::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) diff --git a/src/quicktemplates2/qquickdialogbuttonbox_p.h b/src/quicktemplates2/qquickdialogbuttonbox_p.h index 51ae473f..75c05afb 100644 --- a/src/quicktemplates2/qquickdialogbuttonbox_p.h +++ b/src/quicktemplates2/qquickdialogbuttonbox_p.h @@ -131,6 +131,7 @@ protected: #if QT_CONFIG(accessibility) QAccessible::Role accessibleRole() const override; #endif + bool event(QEvent *e) override; private: Q_DISABLE_COPY(QQuickDialogButtonBox) diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp index cf2f7558..6f804546 100644 --- a/src/quicktemplates2/qquickdrawer.cpp +++ b/src/quicktemplates2/qquickdrawer.cpp @@ -482,6 +482,8 @@ bool QQuickDrawerPrivate::handleMove(QQuickItem *item, const QPointF &point, ulo bool QQuickDrawerPrivate::handleRelease(QQuickItem *item, const QPointF &point, ulong timestamp) { + if (pressPoint.isNull()) + return false; if (!popupItem->keepMouseGrab() && !popupItem->keepTouchGrab()) { velocityCalculator.reset(); return QQuickPopupPrivate::handleRelease(item, point, timestamp); diff --git a/src/quicktemplates2/qquickheaderview.cpp b/src/quicktemplates2/qquickheaderview.cpp index 5c465cc7..d99c09eb 100644 --- a/src/quicktemplates2/qquickheaderview.cpp +++ b/src/quicktemplates2/qquickheaderview.cpp @@ -236,16 +236,11 @@ void QQuickHeaderViewBasePrivate::setModelImpl(const QVariant &newModel) void QQuickHeaderViewBasePrivate::syncModel() { Q_Q(QQuickHeaderViewBase); + if (assignedSyncView && !m_modelExplicitlySetByUser) { auto newModel = assignedSyncView->model(); - if (auto m = newModel.value<QAbstractTableModel *>()) { + if (auto m = newModel.value<QAbstractItemModel *>()) proxyModelSetter(q, m_headerDataProxyModel, m); - } else if (orientation() == Qt::Horizontal) { - if (auto m = newModel.value<QAbstractItemModel *>()) - proxyModelSetter(q, m_transposeProxyModel, m); - } else { - QQuickTableViewPrivate::setModelImpl(newModel); - } } QQuickTableViewPrivate::syncModel(); @@ -369,18 +364,22 @@ QModelIndex QHeaderDataProxyModel::parent(const QModelIndex &child) const return QModelIndex(); } -QModelIndex QHeaderDataProxyModel::sibling(int row, int column, const QModelIndex &idx) const +QModelIndex QHeaderDataProxyModel::sibling(int row, int column, const QModelIndex &) const { - return index(row, column, idx); + return index(row, column); } int QHeaderDataProxyModel::rowCount(const QModelIndex &parent) const { + if (parent.isValid()) + return 0; return m_model.isNull() ? -1 : (m_orientation == Qt::Horizontal ? 1 : m_model->rowCount(parent)); } int QHeaderDataProxyModel::columnCount(const QModelIndex &parent) const { + if (parent.isValid()) + return 0; return m_model.isNull() ? -1 : (m_orientation == Qt::Vertical ? 1 : m_model->columnCount(parent)); } @@ -406,7 +405,8 @@ bool QHeaderDataProxyModel::setData(const QModelIndex &index, const QVariant &va bool QHeaderDataProxyModel::hasChildren(const QModelIndex &parent) const { - Q_UNUSED(parent) + if (!parent.isValid()) + return rowCount(parent) > 0 && columnCount(parent) > 0; return false; } diff --git a/src/quicktemplates2/qquickmenu.cpp b/src/quicktemplates2/qquickmenu.cpp index c3d80aa0..0043dddd 100644 --- a/src/quicktemplates2/qquickmenu.cpp +++ b/src/quicktemplates2/qquickmenu.cpp @@ -170,6 +170,14 @@ static const int SUBMENU_DELAY = 225; Although \l {MenuItem}{MenuItems} are most commonly used with Menu, it can contain any type of item. + \section1 Margins + + As it is inherited from Popup, Menu supports \l {Popup::}{margins}. By + default, all of the built-in styles specify \c 0 for Menu's margins to + ensure that the menu is kept within the bounds of the window. To allow a + menu to go outside of the window (to animate it moving into view, for + example), set the margins property to \c -1. + \sa {Customizing Menu}, MenuItem, {Menu Controls}, {Popup Controls} */ @@ -208,8 +216,12 @@ public: QQuickMenuPrivate::QQuickMenuPrivate() { - Q_Q(QQuickMenu); cascade = shouldCascade(); +} + +void QQuickMenuPrivate::init() +{ + Q_Q(QQuickMenu); contentModel = new QQmlObjectModel(q); } @@ -283,8 +295,8 @@ QQuickItem *QQuickMenuPrivate::beginCreateItem() QQuickItem *item = qobject_cast<QQuickItem *>(object); if (!item) delete object; - - QQml_setParent_noEvent(item, q); + else + QQml_setParent_noEvent(item, q); return item; } @@ -713,9 +725,20 @@ QQuickMenu::QQuickMenu(QObject *parent) { Q_D(QQuickMenu); setFocus(true); + d->init(); connect(d->contentModel, &QQmlObjectModel::countChanged, this, &QQuickMenu::countChanged); } +QQuickMenu::~QQuickMenu() +{ + Q_D(QQuickMenu); + // We have to do this to ensure that the change listeners are removed. + // It's too late to do this in ~QQuickMenuPrivate, as contentModel has already + // been destroyed before that is called. + while (d->contentModel->count() > 0) + d->removeItem(0, d->itemAt(0)); +} + /*! \qmlmethod Item QtQuick.Controls::Menu::itemAt(int index) diff --git a/src/quicktemplates2/qquickmenu_p.h b/src/quicktemplates2/qquickmenu_p.h index 01b970f8..ae653d80 100644 --- a/src/quicktemplates2/qquickmenu_p.h +++ b/src/quicktemplates2/qquickmenu_p.h @@ -76,6 +76,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickMenu : public QQuickPopup public: explicit QQuickMenu(QObject *parent = nullptr); + ~QQuickMenu(); Q_INVOKABLE QQuickItem *itemAt(int index) const; Q_INVOKABLE void addItem(QQuickItem *item); diff --git a/src/quicktemplates2/qquickmenu_p_p.h b/src/quicktemplates2/qquickmenu_p_p.h index ec48c919..63553f8a 100644 --- a/src/quicktemplates2/qquickmenu_p_p.h +++ b/src/quicktemplates2/qquickmenu_p_p.h @@ -73,6 +73,8 @@ public: return menu->d_func(); } + void init(); + QQuickItem *itemAt(int index) const; void insertItem(int index, QQuickItem *item); void moveItem(int from, int to); diff --git a/src/quicktemplates2/qquickoverlay.cpp b/src/quicktemplates2/qquickoverlay.cpp index e9f8801d..91bd5918 100644 --- a/src/quicktemplates2/qquickoverlay.cpp +++ b/src/quicktemplates2/qquickoverlay.cpp @@ -311,6 +311,9 @@ QQuickOverlay::QQuickOverlay(QQuickItem *parent) Q_D(QQuickOverlay); setZ(1000001); // DefaultWindowDecoration+1 setAcceptedMouseButtons(Qt::AllButtons); +#if QT_CONFIG(quicktemplates2_multitouch) + setAcceptTouchEvents(true); +#endif setFiltersChildMouseEvents(true); setVisible(false); @@ -468,22 +471,27 @@ bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event) // background dimming OR over another popup underneath, in case the popup // does not have background dimming. if (item == p->dimmer || !p->popupItem->isAncestorOf(item)) { + bool handled = false; switch (event->type()) { #if QT_CONFIG(quicktemplates2_multitouch) case QEvent::TouchBegin: case QEvent::TouchUpdate: case QEvent::TouchEnd: - return d->handleTouchEvent(item, static_cast<QTouchEvent *>(event), popup); + handled = d->handleTouchEvent(item, static_cast<QTouchEvent *>(event), popup); + break; #endif case QEvent::MouseButtonPress: case QEvent::MouseMove: case QEvent::MouseButtonRelease: - return d->handleMouseEvent(item, static_cast<QMouseEvent *>(event), popup); + handled = d->handleMouseEvent(item, static_cast<QMouseEvent *>(event), popup); + break; default: break; } + if (handled) + return true; } } return false; diff --git a/src/quicktemplates2/qquickpage.cpp b/src/quicktemplates2/qquickpage.cpp index 0a72bad7..bc27740b 100644 --- a/src/quicktemplates2/qquickpage.cpp +++ b/src/quicktemplates2/qquickpage.cpp @@ -244,6 +244,9 @@ QQuickPage::~QQuickPage() The title is often displayed at the top of a page to give the user context about the page they are viewing. + Page does not render the title itself, but instead relies + on the application to do so. For example: + \code ApplicationWindow { visible: true diff --git a/src/quicktemplates2/qquickpageindicator.cpp b/src/quicktemplates2/qquickpageindicator.cpp index a06884cb..4a2b7f14 100644 --- a/src/quicktemplates2/qquickpageindicator.cpp +++ b/src/quicktemplates2/qquickpageindicator.cpp @@ -276,11 +276,17 @@ void QQuickPageIndicator::setInteractive(bool interactive) d->interactive = interactive; if (interactive) { setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(quicktemplates2_multitouch) + setAcceptTouchEvents(true); +#endif #if QT_CONFIG(cursor) setCursor(Qt::ArrowCursor); #endif } else { setAcceptedMouseButtons(Qt::NoButton); +#if QT_CONFIG(quicktemplates2_multitouch) + setAcceptTouchEvents(true); +#endif #if QT_CONFIG(cursor) unsetCursor(); #endif diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp index b5a6e992..7df80a04 100644 --- a/src/quicktemplates2/qquickpopup.cpp +++ b/src/quicktemplates2/qquickpopup.cpp @@ -51,6 +51,8 @@ QT_BEGIN_NAMESPACE +Q_LOGGING_CATEGORY(lcDimmer, "qt.quick.controls.popup.dimmer") + /*! \qmltype Popup \inherits QtObject @@ -215,6 +217,19 @@ QT_BEGIN_NAMESPACE To ensure that the popup is positioned within the bounds of the enclosing window, the \l margins property can be set to a non-negative value. + \section1 Popup Transitions + + Since Qt 5.15.3 the following properties are restored to their original values from before + the enter transition after the exit transition is completed. + + \list + \li \l opacity + \li \l scale + \endlist + + This allows the built-in styles to animate on these properties without losing any explicitly + defined value. + \sa {Popup Controls}, {Customizing Popup}, ApplicationWindow */ @@ -441,6 +456,9 @@ bool QQuickPopupPrivate::prepareEnterTransition() popupItem->setVisible(true); getPositioner()->setParentItem(parentItem); emit q->visibleChanged(); + + if (focus) + popupItem->setFocus(true); } return true; } @@ -451,10 +469,16 @@ bool QQuickPopupPrivate::prepareExitTransition() if (transitionState == ExitTransition && transitionManager.isRunning()) return false; + // We need to cache the original scale and opacity values so we can reset it after + // the exit transition is done so they have the original values again + prevScale = popupItem->scale(); + prevOpacity = popupItem->opacity(); + if (transitionState != ExitTransition) { // The setFocus(false) call below removes any active focus before we're // able to check it in finalizeExitTransition. - hadActiveFocusBeforeExitTransition = popupItem->hasActiveFocus(); + if (!hadActiveFocusBeforeExitTransition) + hadActiveFocusBeforeExitTransition = popupItem->hasActiveFocus(); if (focus) popupItem->setFocus(false); transitionState = ExitTransition; @@ -468,8 +492,6 @@ bool QQuickPopupPrivate::prepareExitTransition() void QQuickPopupPrivate::finalizeEnterTransition() { Q_Q(QQuickPopup); - if (focus) - popupItem->setFocus(true); transitionState = NoTransition; getPositioner()->reposition(); emit q->openedChanged(); @@ -480,8 +502,10 @@ void QQuickPopupPrivate::finalizeExitTransition() { Q_Q(QQuickPopup); getPositioner()->setParentItem(nullptr); - popupItem->setParentItem(nullptr); - popupItem->setVisible(false); + if (popupItem) { + popupItem->setParentItem(nullptr); + popupItem->setVisible(false); + } destroyOverlay(); if (hadActiveFocusBeforeExitTransition && window) { @@ -490,13 +514,14 @@ void QQuickPopupPrivate::finalizeExitTransition() if (QQuickOverlay *overlay = QQuickOverlay::overlay(window)) { const auto stackingOrderPopups = QQuickOverlayPrivate::get(overlay)->stackingOrderPopups(); for (auto popup : stackingOrderPopups) { - if (QQuickPopupPrivate::get(popup)->transitionState != ExitTransition) { + if (QQuickPopupPrivate::get(popup)->transitionState != ExitTransition + && popup->hasFocus()) { nextFocusPopup = popup; break; } } } - if (nextFocusPopup && nextFocusPopup->hasFocus()) { + if (nextFocusPopup) { nextFocusPopup->forceActiveFocus(); } else { QQuickApplicationWindow *applicationWindow = qobject_cast<QQuickApplicationWindow*>(window); @@ -512,6 +537,10 @@ void QQuickPopupPrivate::finalizeExitTransition() hadActiveFocusBeforeExitTransition = false; emit q->visibleChanged(); emit q->closed(); + if (popupItem) { + popupItem->setScale(prevScale); + popupItem->setOpacity(prevOpacity); + } } QMarginsF QQuickPopupPrivate::getMargins() const @@ -574,7 +603,6 @@ void QQuickPopupPrivate::setBottomMargin(qreal value, bool reset) /*! \since QtQuick.Controls 2.5 (Qt 5.12) - \qmlpropertygroup QtQuick.Controls::Popup::anchors \qmlproperty Object QtQuick.Controls::Popup::anchors.centerIn Anchors provide a way to position an item by specifying its @@ -702,6 +730,8 @@ static QQuickItem *createDimmer(QQmlComponent *component, QQuickPopup *popup, QQ if (component) component->completeCreate(); } + qCDebug(lcDimmer) << "finished creating dimmer from component" << component + << "for popup" << popup << "with parent" << parent << "- item is:" << item; return item; } @@ -728,6 +758,7 @@ void QQuickPopupPrivate::createOverlay() void QQuickPopupPrivate::destroyOverlay() { if (dimmer) { + qCDebug(lcDimmer) << "destroying dimmer" << dimmer; dimmer->setParentItem(nullptr); dimmer->deleteLater(); dimmer = nullptr; @@ -826,6 +857,12 @@ QQuickPopup::~QQuickPopup() d->popupItem = nullptr; delete d->positioner; d->positioner = nullptr; + + // If the popup is destroyed before the exit transition finishes, + // the necessary cleanup (removing modal dimmers that block mouse events, + // emitting closed signal, etc.) won't happen. That's why we do it manually here. + if (d->transitionState == QQuickPopupPrivate::ExitTransition && d->transitionManager.isRunning()) + d->finalizeExitTransition(); } /*! diff --git a/src/quicktemplates2/qquickpopup_p_p.h b/src/quicktemplates2/qquickpopup_p_p.h index 8a85f914..ef4b112e 100644 --- a/src/quicktemplates2/qquickpopup_p_p.h +++ b/src/quicktemplates2/qquickpopup_p_p.h @@ -196,6 +196,8 @@ public: QList<QQuickStateAction> exitActions; QQuickPopupTransitionManager transitionManager; QQuickPopupAnchors *anchors = nullptr; + qreal prevOpacity = 0; + qreal prevScale = 0; friend class QQuickPopupTransitionManager; }; diff --git a/src/quicktemplates2/qquickpopupanchors.cpp b/src/quicktemplates2/qquickpopupanchors.cpp index 5acc2934..c7ac038d 100644 --- a/src/quicktemplates2/qquickpopupanchors.cpp +++ b/src/quicktemplates2/qquickpopupanchors.cpp @@ -47,6 +47,15 @@ QQuickPopupAnchors::QQuickPopupAnchors(QQuickPopup *popup) d->popup = popup; } +QQuickPopupAnchors::~QQuickPopupAnchors() +{ + Q_D(const QQuickPopupAnchors); + if (d->centerIn) { + auto centerInPrivate = QQuickItemPrivate::get(d->centerIn); + centerInPrivate->removeItemChangeListener(this, QQuickItemPrivate::Destroyed); + } +} + QQuickItem *QQuickPopupAnchors::centerIn() const { Q_D(const QQuickPopupAnchors); @@ -59,8 +68,20 @@ void QQuickPopupAnchors::setCenterIn(QQuickItem *item) if (item == d->centerIn) return; + if (d->centerIn) { + auto centerInPrivate = QQuickItemPrivate::get(d->centerIn); + centerInPrivate->removeItemChangeListener(this, QQuickItemPrivate::Destroyed); + } + d->centerIn = item; + + if (d->centerIn) { + auto centerInPrivate = QQuickItemPrivate::get(d->centerIn); + centerInPrivate->addItemChangeListener(this, QQuickItemPrivate::Destroyed); + } + QQuickPopupPrivate::get(d->popup)->reposition(); + emit centerInChanged(); } @@ -69,4 +90,9 @@ void QQuickPopupAnchors::resetCenterIn() setCenterIn(nullptr); } +void QQuickPopupAnchors::itemDestroyed(QQuickItem *) +{ + resetCenterIn(); +} + QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickpopupanchors_p.h b/src/quicktemplates2/qquickpopupanchors_p.h index 531c494e..eff4e23d 100644 --- a/src/quicktemplates2/qquickpopupanchors_p.h +++ b/src/quicktemplates2/qquickpopupanchors_p.h @@ -50,6 +50,7 @@ #include <QtCore/qobject.h> #include <QtQml/qqml.h> +#include <QtQuick/private/qquickitem_p.h> #include <QtQuickTemplates2/private/qtquicktemplates2global_p.h> QT_BEGIN_NAMESPACE @@ -58,13 +59,14 @@ class QQuickItem; class QQuickPopupAnchorsPrivate; class QQuickPopup; -class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickPopupAnchors : public QObject +class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickPopupAnchors : public QObject, public QQuickItemChangeListener { Q_OBJECT Q_PROPERTY(QQuickItem *centerIn READ centerIn WRITE setCenterIn RESET resetCenterIn NOTIFY centerInChanged) public: explicit QQuickPopupAnchors(QQuickPopup *popup); + ~QQuickPopupAnchors(); QQuickItem *centerIn() const; void setCenterIn(QQuickItem *item); @@ -74,6 +76,8 @@ Q_SIGNALS: void centerInChanged(); private: + void itemDestroyed(QQuickItem *item) override; + Q_DISABLE_COPY(QQuickPopupAnchors) Q_DECLARE_PRIVATE(QQuickPopupAnchors) }; diff --git a/src/quicktemplates2/qquickpopupitem.cpp b/src/quicktemplates2/qquickpopupitem.cpp index 8e169b0b..0069b9fc 100644 --- a/src/quicktemplates2/qquickpopupitem.cpp +++ b/src/quicktemplates2/qquickpopupitem.cpp @@ -164,6 +164,9 @@ QQuickPopupItem::QQuickPopupItem(QQuickPopup *popup) setParent(popup); setFlag(ItemIsFocusScope); setAcceptedMouseButtons(Qt::AllButtons); +#if QT_CONFIG(quicktemplates2_multitouch) + setAcceptTouchEvents(true); +#endif #if QT_CONFIG(cursor) setCursor(Qt::ArrowCursor); #endif diff --git a/src/quicktemplates2/qquickpopuppositioner.cpp b/src/quicktemplates2/qquickpopuppositioner.cpp index dbe8ac1d..1bfaafbe 100644 --- a/src/quicktemplates2/qquickpopuppositioner.cpp +++ b/src/quicktemplates2/qquickpopuppositioner.cpp @@ -92,7 +92,10 @@ void QQuickPopupPositioner::setParentItem(QQuickItem *parent) QQuickItemPrivate::get(parent)->addItemChangeListener(this, ItemChangeTypes); addAncestorListeners(parent->parentItem()); - + // Store the scale property so the end result of any transition that could effect the scale + // does not influence the top left of the final popup, so it doesn't appear to flip from one + // position to another as a result + m_popupScale = m_popup->popupItem()->scale(); if (m_popup->popupItem()->isVisible()) QQuickPopupPrivate::get(m_popup)->reposition(); } @@ -108,11 +111,10 @@ void QQuickPopupPositioner::reposition() return; } - const qreal scale = popupItem->scale(); - const qreal w = popupItem->width() * scale; - const qreal h = popupItem->height() * scale; - const qreal iw = popupItem->implicitWidth() * scale; - const qreal ih = popupItem->implicitHeight() * scale; + const qreal w = popupItem->width() * m_popupScale; + const qreal h = popupItem->height() * m_popupScale; + const qreal iw = popupItem->implicitWidth() * m_popupScale; + const qreal ih = popupItem->implicitHeight() * m_popupScale; bool widthAdjusted = false; bool heightAdjusted = false; @@ -258,9 +260,9 @@ void QQuickPopupPositioner::reposition() } if (!p->hasWidth && widthAdjusted && rect.width() > 0) - popupItem->setWidth(rect.width() / scale); + popupItem->setWidth(rect.width() / m_popupScale); if (!p->hasHeight && heightAdjusted && rect.height() > 0) - popupItem->setHeight(rect.height() / scale); + popupItem->setHeight(rect.height() / m_popupScale); m_positioning = false; } diff --git a/src/quicktemplates2/qquickpopuppositioner_p_p.h b/src/quicktemplates2/qquickpopuppositioner_p_p.h index 64f57a3f..03a2e2fe 100644 --- a/src/quicktemplates2/qquickpopuppositioner_p_p.h +++ b/src/quicktemplates2/qquickpopuppositioner_p_p.h @@ -79,6 +79,7 @@ protected: bool m_positioning = false; QQuickItem *m_parentItem = nullptr; QQuickPopup *m_popup = nullptr; + qreal m_popupScale = 1.0; }; QT_END_NAMESPACE diff --git a/src/quicktemplates2/qquickrangeslider.cpp b/src/quicktemplates2/qquickrangeslider.cpp index 9ad12102..f1e5c805 100644 --- a/src/quicktemplates2/qquickrangeslider.cpp +++ b/src/quicktemplates2/qquickrangeslider.cpp @@ -625,6 +625,9 @@ QQuickRangeSlider::QQuickRangeSlider(QQuickItem *parent) setFlag(QQuickItem::ItemIsFocusScope); setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(quicktemplates2_multitouch) + setAcceptTouchEvents(true); +#endif #if QT_CONFIG(cursor) setCursor(Qt::ArrowCursor); #endif @@ -662,6 +665,10 @@ void QQuickRangeSlider::setFrom(qreal from) if (isComponentComplete()) { d->first->setValue(d->first->value()); d->second->setValue(d->second->value()); + auto *firstPrivate = QQuickRangeSliderNodePrivate::get(d->first); + auto *secondPrivate = QQuickRangeSliderNodePrivate::get(d->second); + firstPrivate->updatePosition(true); + secondPrivate->updatePosition(); } } @@ -690,6 +697,10 @@ void QQuickRangeSlider::setTo(qreal to) if (isComponentComplete()) { d->first->setValue(d->first->value()); d->second->setValue(d->second->value()); + auto *firstPrivate = QQuickRangeSliderNodePrivate::get(d->first); + auto *secondPrivate = QQuickRangeSliderNodePrivate::get(d->second); + firstPrivate->updatePosition(true); + secondPrivate->updatePosition(); } } @@ -743,7 +754,6 @@ qreal QQuickRangeSlider::valueAt(qreal position) const } /*! - \qmlpropertygroup QtQuick.Controls::RangeSlider::first \qmlproperty real QtQuick.Controls::RangeSlider::first.value \qmlproperty real QtQuick.Controls::RangeSlider::first.position \qmlproperty real QtQuick.Controls::RangeSlider::first.visualPosition @@ -822,7 +832,6 @@ QQuickRangeSliderNode *QQuickRangeSlider::first() const */ /*! - \qmlpropertygroup QtQuick.Controls::RangeSlider::second \qmlproperty real QtQuick.Controls::RangeSlider::second.value \qmlproperty real QtQuick.Controls::RangeSlider::second.position \qmlproperty real QtQuick.Controls::RangeSlider::second.visualPosition diff --git a/src/quicktemplates2/qquickscrollbar.cpp b/src/quicktemplates2/qquickscrollbar.cpp index 678b7942..f0783708 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 @@ -205,11 +205,17 @@ void QQuickScrollBarPrivate::setInteractive(bool enabled) interactive = enabled; if (interactive) { q->setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(quicktemplates2_multitouch) + q->setAcceptTouchEvents(true); +#endif #if QT_CONFIG(cursor) q->setCursor(Qt::ArrowCursor); #endif } else { q->setAcceptedMouseButtons(Qt::NoButton); +#if QT_CONFIG(quicktemplates2_multitouch) + q->setAcceptTouchEvents(false); +#endif #if QT_CONFIG(cursor) q->unsetCursor(); #endif @@ -303,6 +309,9 @@ QQuickScrollBar::QQuickScrollBar(QQuickItem *parent) { setKeepMouseGrab(true); setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(quicktemplates2_multitouch) + setAcceptTouchEvents(true); +#endif #if QT_CONFIG(cursor) setCursor(Qt::ArrowCursor); #endif @@ -788,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<QQuickControl*>(q_func()->parent())) + QQuickControlPrivate::unhideOldItem(control, horizontal); + layoutHorizontal(); horizontal->setSize(area->property("widthRatio").toReal()); horizontal->setPosition(area->property("xPosition").toReal()); @@ -809,6 +826,9 @@ void QQuickScrollBarAttachedPrivate::initVertical() if (parent && parent == flickable->parentItem()) vertical->stackAfter(flickable); + if (auto control = qobject_cast<QQuickControl*>(q_func()->parent())) + QQuickControlPrivate::unhideOldItem(control, vertical); + layoutVertical(); vertical->setSize(area->property("heightRatio").toReal()); vertical->setPosition(area->property("yPosition").toReal()); @@ -818,6 +838,16 @@ void QQuickScrollBarAttachedPrivate::cleanupHorizontal() { Q_ASSERT(flickable && horizontal); + QQuickControlPrivate::hideOldItem(horizontal); + // ScrollBar.qml has a binding to visible and ScrollView.qml has a binding to parent. + // If we just set visible to false and parent to null, these bindings will overwrite + // them upon component completion as part of the binding evaluation. + // That's why we remove the binding completely. + const QQmlProperty visibleProperty(horizontal, QStringLiteral("visible")); + const QQmlProperty parentProperty(horizontal, QStringLiteral("parent")); + QQmlPropertyPrivate::removeBinding(visibleProperty); + QQmlPropertyPrivate::removeBinding(parentProperty); + disconnect(flickable, &QQuickFlickable::movingHorizontallyChanged, this, &QQuickScrollBarAttachedPrivate::activateHorizontal); // TODO: export QQuickFlickableVisibleArea @@ -830,6 +860,12 @@ void QQuickScrollBarAttachedPrivate::cleanupVertical() { Q_ASSERT(flickable && vertical); + QQuickControlPrivate::hideOldItem(vertical); + const QQmlProperty visibleProperty(vertical, QStringLiteral("visible")); + const QQmlProperty parentProperty(vertical, QStringLiteral("parent")); + QQmlPropertyPrivate::removeBinding(visibleProperty); + QQmlPropertyPrivate::removeBinding(parentProperty); + disconnect(flickable, &QQuickFlickable::movingVerticallyChanged, this, &QQuickScrollBarAttachedPrivate::activateVertical); // TODO: export QQuickFlickableVisibleArea @@ -860,6 +896,9 @@ class QQuickFriendlyFlickable : public QQuickFlickable void QQuickScrollBarAttachedPrivate::scrollHorizontal() { + if (!flickable) + return; + QQuickFriendlyFlickable *f = reinterpret_cast<QQuickFriendlyFlickable *>(flickable); const qreal viewwidth = f->width(); @@ -872,6 +911,9 @@ void QQuickScrollBarAttachedPrivate::scrollHorizontal() void QQuickScrollBarAttachedPrivate::scrollVertical() { + if (!flickable) + return; + QQuickFriendlyFlickable *f = reinterpret_cast<QQuickFriendlyFlickable *>(flickable); const qreal viewheight = f->height(); diff --git a/src/quicktemplates2/qquickscrollbar_p_p.h b/src/quicktemplates2/qquickscrollbar_p_p.h index 5c7628b9..c58c2ed1 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/src/quicktemplates2/qquickscrollview.cpp b/src/quicktemplates2/qquickscrollview.cpp index f9f4c9f8..01e19b16 100644 --- a/src/quicktemplates2/qquickscrollview.cpp +++ b/src/quicktemplates2/qquickscrollview.cpp @@ -38,6 +38,7 @@ #include "qquickpane_p_p.h" #include "qquickscrollbar_p_p.h" +#include <QtQml/qqmlinfo.h> #include <QtQuick/private/qquickflickable_p.h> QT_BEGIN_NAMESPACE @@ -82,7 +83,13 @@ QT_BEGIN_NAMESPACE \l {QtQuick.Controls::Pane::}{contentHeight} properties must be set to the combined size of its contained items. \li If the content size is less than or equal to the size of the ScrollView, - it will not be flickable. + it will not be scrollable. + \li If you want the ScrollView to only scroll vertically, you can bind + \l {QtQuick.Controls::Pane::}{contentWidth} to + \l {QtQuick.Controls::Control::}{availableWidth} + (and vice versa for contentHeight). This will let the contents fill + out all the available space horizontally inside the ScrollView, taking + any padding or scroll bars into account. \endlist \section2 Scroll Bars @@ -569,7 +576,10 @@ void QQuickScrollView::contentItemChange(QQuickItem *newItem, QQuickItem *oldIte // assume/require that it has an explicit content size assigned. d->flickableHasExplicitContentWidth = true; d->flickableHasExplicitContentHeight = true; - d->setFlickable(qobject_cast<QQuickFlickable *>(newItem), false); + auto newItemAsFlickable = qobject_cast<QQuickFlickable *>(newItem); + if (newItem && !newItemAsFlickable) + qmlWarning(this) << "ScrollView only supports Flickable types as its contentItem"; + d->setFlickable(newItemAsFlickable, false); } QQuickPane::contentItemChange(newItem, oldItem); } diff --git a/src/quicktemplates2/qquickslider.cpp b/src/quicktemplates2/qquickslider.cpp index f4a459fa..ddb4c434 100644 --- a/src/quicktemplates2/qquickslider.cpp +++ b/src/quicktemplates2/qquickslider.cpp @@ -274,6 +274,9 @@ QQuickSlider::QQuickSlider(QQuickItem *parent) setActiveFocusOnTab(true); setFocusPolicy(Qt::StrongFocus); setAcceptedMouseButtons(Qt::LeftButton); +#if QT_CONFIG(quicktemplates2_multitouch) + setAcceptTouchEvents(true); +#endif #if QT_CONFIG(cursor) setCursor(Qt::ArrowCursor); #endif diff --git a/src/quicktemplates2/qquickspinbox.cpp b/src/quicktemplates2/qquickspinbox.cpp index 3482af8c..a3a73472 100644 --- a/src/quicktemplates2/qquickspinbox.cpp +++ b/src/quicktemplates2/qquickspinbox.cpp @@ -117,8 +117,8 @@ public: int effectiveStepSize() const; - void updateDisplayText(); - void setDisplayText(const QString &displayText); + void updateDisplayText(bool modified = false); + void setDisplayText(const QString &displayText, bool modified = false); bool upEnabled() const; void updateUpEnabled(); @@ -209,24 +209,34 @@ void QQuickSpinBoxPrivate::updateValue() } } +// modified indicates if the value was modified by the user and not programatically +// this is then passed on to updateDisplayText to indicate that the user has modified +// the value so it may need to trigger an update of the contentItem's text too + bool QQuickSpinBoxPrivate::setValue(int newValue, bool allowWrap, bool modified) { Q_Q(QQuickSpinBox); + int correctedValue = newValue; if (q->isComponentComplete()) - newValue = boundValue(newValue, allowWrap); + correctedValue = boundValue(newValue, allowWrap); - if (value == newValue) + if (!modified && newValue == correctedValue && newValue == value) return false; - value = newValue; + const bool emitSignals = (value != correctedValue); + value = correctedValue; - updateDisplayText(); + updateDisplayText(modified); updateUpEnabled(); updateDownEnabled(); - emit q->valueChanged(); - if (modified) - emit q->valueModified(); + // Only emit the signals if the corrected value is not the same as the + // original value to avoid unnecessary updates + if (emitSignals) { + emit q->valueChanged(); + if (modified) + emit q->valueModified(); + } return true; } @@ -250,7 +260,7 @@ int QQuickSpinBoxPrivate::effectiveStepSize() const return from > to ? -1 * stepSize : stepSize; } -void QQuickSpinBoxPrivate::updateDisplayText() +void QQuickSpinBoxPrivate::updateDisplayText(bool modified) { Q_Q(QQuickSpinBox); QString text; @@ -262,13 +272,14 @@ void QQuickSpinBoxPrivate::updateDisplayText() } else { text = locale.toString(value); } - setDisplayText(text); + setDisplayText(text, modified); } -void QQuickSpinBoxPrivate::setDisplayText(const QString &text) +void QQuickSpinBoxPrivate::setDisplayText(const QString &text, bool modified) { Q_Q(QQuickSpinBox); - if (displayText == text) + + if (!modified && displayText == text) return; displayText = text; @@ -698,7 +709,7 @@ QJSValue QQuickSpinBox::valueFromText() const if (!d->valueFromText.isCallable()) { QQmlEngine *engine = qmlEngine(this); if (engine) - d->valueFromText = engine->evaluate(QStringLiteral("function(text, locale) { return Number.fromLocaleString(locale, text); }")); + d->valueFromText = engine->evaluate(QStringLiteral("(function(text, locale) { return Number.fromLocaleString(locale, text); })")); } return d->valueFromText; } @@ -715,7 +726,6 @@ void QQuickSpinBox::setValueFromText(const QJSValue &callback) } /*! - \qmlpropertygroup QtQuick.Controls::SpinBox::up \qmlproperty bool QtQuick.Controls::SpinBox::up.pressed \qmlproperty Item QtQuick.Controls::SpinBox::up.indicator \qmlproperty bool QtQuick.Controls::SpinBox::up.hovered @@ -736,7 +746,6 @@ QQuickSpinButton *QQuickSpinBox::up() const } /*! - \qmlpropertygroup QtQuick.Controls::SpinBox::down \qmlproperty bool QtQuick.Controls::SpinBox::down.pressed \qmlproperty Item QtQuick.Controls::SpinBox::down.indicator \qmlproperty bool QtQuick.Controls::SpinBox::down.hovered diff --git a/src/quicktemplates2/qquicksplitview.cpp b/src/quicktemplates2/qquicksplitview.cpp index a3566c56..a06c8d31 100644 --- a/src/quicktemplates2/qquicksplitview.cpp +++ b/src/quicktemplates2/qquicksplitview.cpp @@ -49,7 +49,7 @@ QT_BEGIN_NAMESPACE /*! \qmltype SplitView - \inherits Control + \inherits Container //! \instantiates QQuickSplitView \inqmlmodule QtQuick.Controls \since 5.13 diff --git a/src/quicktemplates2/qquickstackview.cpp b/src/quicktemplates2/qquickstackview.cpp index 4c314904..135107ea 100644 --- a/src/quicktemplates2/qquickstackview.cpp +++ b/src/quicktemplates2/qquickstackview.cpp @@ -558,7 +558,14 @@ QQuickItem *QQuickStackView::find(const QJSValue &callback, LoadBehavior behavio void QQuickStackView::push(QQmlV4Function *args) { Q_D(QQuickStackView); - QScopedValueRollback<QString> rollback(d->operation, QStringLiteral("push")); + const QString operationName = QStringLiteral("push"); + if (d->modifyingElements) { + d->warnOfInterruption(operationName); + return; + } + + QScopedValueRollback<bool> modifyingElements(d->modifyingElements, true); + QScopedValueRollback<QString> operationNameRollback(d->operation, operationName); if (args->length() <= 0) { d->warn(QStringLiteral("missing arguments")); args->setReturnValue(QV4::Encode::null()); @@ -627,6 +634,9 @@ void QQuickStackView::push(QQmlV4Function *args) items down to (but not including) the first item is popped. If not specified, only the current item is popped. + \note A pop() operation on a stack with depth 1 or 0 does nothing. In such + cases, the stack can be emptied using the \l clear() method. + \include qquickstackview.qdocinc pop-ownership An \a operation can be optionally specified as the last argument. Supported @@ -651,14 +661,15 @@ void QQuickStackView::push(QQmlV4Function *args) void QQuickStackView::pop(QQmlV4Function *args) { Q_D(QQuickStackView); - if (d->removingElements) { - d->warn(QStringLiteral("cannot pop while already in the process of removing elements")); + const QString operationName = QStringLiteral("pop"); + if (d->modifyingElements) { + d->warnOfInterruption(operationName); args->setReturnValue(QV4::Encode::null()); return; } - QScopedValueRollback<bool> removingElements(d->removingElements, true); - QScopedValueRollback<QString> rollback(d->operation, QStringLiteral("pop")); + QScopedValueRollback<bool> modifyingElements(d->modifyingElements, true); + QScopedValueRollback<QString> operationNameRollback(d->operation, operationName); int argc = args->length(); if (d->elements.count() <= 1 || argc > 2) { if (argc > 2) @@ -813,14 +824,15 @@ void QQuickStackView::pop(QQmlV4Function *args) void QQuickStackView::replace(QQmlV4Function *args) { Q_D(QQuickStackView); - if (d->removingElements) { - d->warn(QStringLiteral("cannot replace while already in the process of removing elements")); + const QString operationName = QStringLiteral("replace"); + if (d->modifyingElements) { + d->warnOfInterruption(operationName); args->setReturnValue(QV4::Encode::null()); return; } - QScopedValueRollback<bool> removingElements(d->removingElements, true); - QScopedValueRollback<QString> rollback(d->operation, QStringLiteral("replace")); + QScopedValueRollback<bool> modifyingElements(d->modifyingElements, true); + QScopedValueRollback<QString> operationNameRollback(d->operation, operationName); if (args->length() <= 0) { d->warn(QStringLiteral("missing arguments")); args->setReturnValue(QV4::Encode::null()); @@ -916,12 +928,14 @@ void QQuickStackView::clear(Operation operation) if (d->elements.isEmpty()) return; - if (d->removingElements) { - d->warn(QStringLiteral("cannot clear while already in the process of removing elements")); + const QString operationName = QStringLiteral("clear"); + if (d->modifyingElements) { + d->warnOfInterruption(operationName); return; } - QScopedValueRollback<bool> removingElements(d->removingElements, true); + QScopedValueRollback<bool> modifyingElements(d->modifyingElements, true); + QScopedValueRollback<QString> operationNameRollback(d->operation, operationName); if (operation != Immediate) { QQuickStackElement *exit = d->elements.pop(); exit->removal = true; @@ -1128,7 +1142,7 @@ void QQuickStackView::componentComplete() QQuickControl::componentComplete(); Q_D(QQuickStackView); - QScopedValueRollback<QString> rollback(d->operation, QStringLiteral("initialItem")); + QScopedValueRollback<QString> operationNameRollback(d->operation, QStringLiteral("initialItem")); QQuickStackElement *element = nullptr; QString error; int oldDepth = d->elements.count(); diff --git a/src/quicktemplates2/qquickstackview_p.cpp b/src/quicktemplates2/qquickstackview_p.cpp index a280e31d..e9dc5f35 100644 --- a/src/quicktemplates2/qquickstackview_p.cpp +++ b/src/quicktemplates2/qquickstackview_p.cpp @@ -56,6 +56,12 @@ void QQuickStackViewPrivate::warn(const QString &error) qmlWarning(q) << operation << ": " << error; } +void QQuickStackViewPrivate::warnOfInterruption(const QString &attemptedOperation) +{ + Q_Q(QQuickStackView); + qmlWarning(q) << "cannot " << attemptedOperation << " while already in the process of completing a " << operation; +} + void QQuickStackViewPrivate::setCurrentItem(QQuickStackElement *element) { Q_Q(QQuickStackView); diff --git a/src/quicktemplates2/qquickstackview_p_p.h b/src/quicktemplates2/qquickstackview_p_p.h index b8c4b817..98f9cb98 100644 --- a/src/quicktemplates2/qquickstackview_p_p.h +++ b/src/quicktemplates2/qquickstackview_p_p.h @@ -73,6 +73,7 @@ public: } void warn(const QString &error); + void warnOfInterruption(const QString &attemptedOperation); void setCurrentItem(QQuickStackElement *element); @@ -94,7 +95,7 @@ public: void depthChange(int newDepth, int oldDepth); bool busy = false; - bool removingElements = false; + bool modifyingElements = false; QString operation; QJSValue initialItem; QQuickItem *currentItem = nullptr; @@ -114,7 +115,7 @@ public: return attached->d_func(); } - void itemParentChanged(QQuickItem *item, QQuickItem *parent); + void itemParentChanged(QQuickItem *item, QQuickItem *parent) override; bool explicitVisible = false; QQuickStackElement *element = nullptr; diff --git a/src/quicktemplates2/qquickswipedelegate.cpp b/src/quicktemplates2/qquickswipedelegate.cpp index 30616f7a..629bf23d 100644 --- a/src/quicktemplates2/qquickswipedelegate.cpp +++ b/src/quicktemplates2/qquickswipedelegate.cpp @@ -697,6 +697,11 @@ void QQuickSwipe::close() if (qFuzzyIsNull(d->position)) return; + if (d->control->isPressed()) { + // We don't support closing when we're pressed; release() or clicked() should be used instead. + return; + } + d->beginTransition(0.0); d->wasComplete = false; d->positionBeforePress = 0.0; @@ -708,6 +713,29 @@ QQuickSwipeDelegatePrivate::QQuickSwipeDelegatePrivate(QQuickSwipeDelegate *cont { } +void QQuickSwipeDelegatePrivate::resizeBackground() +{ + if (!background) + return; + + resizingBackground = true; + + QQuickItemPrivate *p = QQuickItemPrivate::get(background); + const bool extraAllocated = extra.isAllocated(); + // Don't check for or set the x here since it will just be overwritten by reposition(). + if (((!p->widthValid || !extraAllocated || !extra->hasBackgroundWidth)) + || (extraAllocated && (extra->hasLeftInset || extra->hasRightInset))) { + background->setWidth(width - getLeftInset() - getRightInset()); + } + if (((!p->heightValid || !extraAllocated || !extra->hasBackgroundHeight) && qFuzzyIsNull(background->y())) + || (extraAllocated && (extra->hasTopInset || extra->hasBottomInset))) { + background->setY(getTopInset()); + background->setHeight(height - getTopInset() - getBottomInset()); + } + + resizingBackground = false; +} + bool QQuickSwipeDelegatePrivate::handleMousePressEvent(QQuickItem *item, QMouseEvent *event) { Q_Q(QQuickSwipeDelegate); @@ -773,9 +801,10 @@ bool QQuickSwipeDelegatePrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEv const QPointF mappedEventPos = item->mapToItem(q, event->pos()); const qreal distance = (mappedEventPos - pressPoint).x(); if (!q->keepMouseGrab()) { - // Taken from QQuickDrawerPrivate::grabMouse; see comments there. - int threshold = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5); - const bool overThreshold = QQuickWindowPrivate::dragOverThreshold(distance, Qt::XAxis, event, threshold); + // We used to use the custom threshold that QQuickDrawerPrivate::grabMouse used, + // but since it's larger than what Flickable uses, it results in Flickable + // stealing events from us (QTBUG-50045), so now we use the default. + const bool overThreshold = QQuickWindowPrivate::dragOverThreshold(distance, Qt::XAxis, event); if (window && overThreshold) { QQuickItem *grabber = q->window()->mouseGrabberItem(); if (!grabber || !grabber->keepMouseGrab()) { @@ -889,7 +918,11 @@ bool QQuickSwipeDelegatePrivate::handleMouseReleaseEvent(QQuickItem *item, QMous swipePrivate->beginTransition(-1.0); swipePrivate->wasComplete = true; } else if (!swipePrivate->isTransitioning()) { - swipePrivate->beginTransition(0.0); + // The position is either <= 0.5 or >= -0.5, so the position should go to 0. + // However, if the position was already 0 or close to it, we were just clicked, + // and we don't need to start a transition. + if (!qFuzzyIsNull(swipePrivate->position)) + swipePrivate->beginTransition(0.0); swipePrivate->wasComplete = false; } @@ -926,13 +959,15 @@ void QQuickSwipeDelegatePrivate::resizeContent() // If the background and contentItem are repositioned due to a swipe, // we don't want to call QQuickControlPrivate's implementation of this function, // as it repositions the contentItem to be visible. - // However, we still want to resize the control vertically. + // However, we still want to position the contentItem vertically + // and resize it (in case the control was resized while open). QQuickSwipePrivate *swipePrivate = QQuickSwipePrivate::get(&swipe); if (!swipePrivate->complete) { QQuickItemDelegatePrivate::resizeContent(); } else if (contentItem) { Q_Q(QQuickSwipeDelegate); contentItem->setY(q->topPadding()); + contentItem->setWidth(q->availableWidth()); contentItem->setHeight(q->availableHeight()); } } @@ -1016,7 +1051,6 @@ QQuickSwipeDelegate::QQuickSwipeDelegate(QQuickItem *parent) */ /*! - \qmlpropertygroup QtQuick.Controls::SwipeDelegate::swipe \qmlproperty real QtQuick.Controls::SwipeDelegate::swipe.position \qmlproperty bool QtQuick.Controls::SwipeDelegate::swipe.complete \qmlproperty bool QtQuick.Controls::SwipeDelegate::swipe.enabled diff --git a/src/quicktemplates2/qquickswipedelegate_p_p.h b/src/quicktemplates2/qquickswipedelegate_p_p.h index 78c72ec8..95a999a0 100644 --- a/src/quicktemplates2/qquickswipedelegate_p_p.h +++ b/src/quicktemplates2/qquickswipedelegate_p_p.h @@ -67,6 +67,7 @@ public: bool handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event); void resizeContent() override; + void resizeBackground() override; QQuickSwipe swipe; }; diff --git a/src/quicktemplates2/qquickswipeview.cpp b/src/quicktemplates2/qquickswipeview.cpp index dab20b93..98d4d22b 100644 --- a/src/quicktemplates2/qquickswipeview.cpp +++ b/src/quicktemplates2/qquickswipeview.cpp @@ -310,7 +310,6 @@ void QQuickSwipeView::geometryChanged(const QRectF &newGeometry, const QRectF &o void QQuickSwipeView::itemAdded(int index, QQuickItem *item) { Q_D(QQuickSwipeView); - QQuickItemPrivate::get(item)->setCulled(true); // QTBUG-51078, QTBUG-51669 if (isComponentComplete()) item->setSize(QSizeF(d->contentItem->width(), d->contentItem->height())); QQuickSwipeViewAttached *attached = qobject_cast<QQuickSwipeViewAttached *>(qmlAttachedPropertiesObject<QQuickSwipeView>(item)); diff --git a/src/quicktemplates2/qquicktextarea.cpp b/src/quicktemplates2/qquicktextarea.cpp index 56dc946d..64fc631d 100644 --- a/src/quicktemplates2/qquicktextarea.cpp +++ b/src/quicktemplates2/qquicktextarea.cpp @@ -219,16 +219,25 @@ void QQuickTextAreaPrivate::resizeBackground() resizingBackground = true; + // When using the attached property TextArea.flickable, we reparent the background out + // of TextArea and into the Flickable since we don't want the background to move while + // flicking. This means that the size of the background should also follow the size of + // the Flickable rather than the size of the TextArea. + const auto flickable = qobject_cast<QQuickFlickable *>(background->parentItem()); + QQuickItemPrivate *p = QQuickItemPrivate::get(background); if (((!p->widthValid || !extra.isAllocated() || !extra->hasBackgroundWidth) && qFuzzyIsNull(background->x())) || (extra.isAllocated() && (extra->hasLeftInset || extra->hasRightInset))) { + const qreal bgWidth = flickable ? flickable->width() : width; background->setX(getLeftInset()); - background->setWidth(width - getLeftInset() - getRightInset()); + background->setWidth(bgWidth - getLeftInset() - getRightInset()); } + if (((!p->heightValid || !extra.isAllocated() || !extra->hasBackgroundHeight) && qFuzzyIsNull(background->y())) || (extra.isAllocated() && (extra->hasTopInset || extra->hasBottomInset))) { + const qreal bgHeight = flickable ? flickable->height() : height; background->setY(getTopInset()); - background->setHeight(height - getTopInset() - getBottomInset()); + background->setHeight(bgHeight - getTopInset() - getBottomInset()); } resizingBackground = false; @@ -349,6 +358,7 @@ void QQuickTextAreaPrivate::attachFlickable(QQuickFlickable *item) QObject::connect(flickable, &QQuickFlickable::contentYChanged, q, &QQuickItem::update); QQuickItemPrivate::get(flickable)->updateOrAddGeometryChangeListener(this, QQuickGeometryChange::Size); + QQuickItemPrivate::get(flickable)->addItemChangeListener(this, QQuickItemPrivate::Destroyed); QObjectPrivate::connect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl); QObjectPrivate::connect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl); @@ -369,6 +379,7 @@ void QQuickTextAreaPrivate::detachFlickable() QObject::disconnect(flickable, &QQuickFlickable::contentYChanged, q, &QQuickItem::update); QQuickItemPrivate::get(flickable)->updateOrRemoveGeometryChangeListener(this, QQuickGeometryChange::Nothing); + QQuickItemPrivate::get(flickable)->removeItemChangeListener(this, QQuickItemPrivate::Destroyed); QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl); QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl); @@ -553,6 +564,8 @@ void QQuickTextAreaPrivate::itemDestroyed(QQuickItem *item) background = nullptr; emit q->implicitBackgroundWidthChanged(); emit q->implicitBackgroundHeightChanged(); + } else if (item == flickable) { + detachFlickable(); } } @@ -1073,7 +1086,11 @@ QSGNode *QQuickTextArea::updatePaintNode(QSGNode *oldNode, UpdatePaintNodeData * if (d->flickable) clipper = d->flickable; - const QRectF cr = clipper->clipRect().adjusted(leftPadding(), topPadding(), -rightPadding(), -bottomPadding()); + const QRectF cr = clipper->clipRect().adjusted( + leftPadding(), topPadding(), + (!d->cursorItem && effectiveHAlign() == HAlignment::AlignRight ? 1 : 0) - rightPadding(), + -bottomPadding()); + clipNode->setRect(!d->flickable ? cr : cr.translated(d->flickable->contentX(), d->flickable->contentY())); clipNode->update(); diff --git a/src/quicktemplates2/qquicktumbler.cpp b/src/quicktemplates2/qquicktumbler.cpp index c1d1c00f..35ed9680 100644 --- a/src/quicktemplates2/qquicktumbler.cpp +++ b/src/quicktemplates2/qquicktumbler.cpp @@ -662,8 +662,9 @@ void QQuickTumblerPrivate::syncCurrentIndex() return; } - // PathView likes to use 0 as currentIndex for empty models, but we use -1 for that. - if (q->count() == 0 && actualViewIndex == 0) + // actualViewIndex might be 0 or -1 for PathView and ListView respectively, + // but we always use -1 for that. + if (q->count() == 0 && actualViewIndex <= 0) return; ignoreCurrentIndexChanges = true; diff --git a/src/quicktemplates2/qtquicktemplates2global.cpp b/src/quicktemplates2/qtquicktemplates2global.cpp new file mode 100644 index 00000000..5d7816b4 --- /dev/null +++ b/src/quicktemplates2/qtquicktemplates2global.cpp @@ -0,0 +1,63 @@ +/**************************************************************************** +** +** Copyright (C) 2021 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtQuick module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ +#include "qquickpage_p.h" +#include "accessible/qaccessiblequickpage_p.h" + +QT_BEGIN_NAMESPACE + +#if QT_CONFIG(accessibility) +static QAccessibleInterface *qQuickAccessibleFactory(const QString &classname, QObject *object) +{ + if (classname == u"QQuickPage") { + return new QAccessibleQuickPage(qobject_cast<QQuickPage *>(object)); + } + return nullptr; +} +#endif + +void QQuickTemplates_initializeModule() +{ +#if QT_CONFIG(accessibility) + QAccessible::installFactory(&qQuickAccessibleFactory); +#endif +} + +Q_CONSTRUCTOR_FUNCTION(QQuickTemplates_initializeModule) + +QT_END_NAMESPACE diff --git a/src/quicktemplates2/qtquicktemplates2global_p.h b/src/quicktemplates2/qtquicktemplates2global_p.h index e5ee3f2e..9b6610dd 100644 --- a/src/quicktemplates2/qtquicktemplates2global_p.h +++ b/src/quicktemplates2/qtquicktemplates2global_p.h @@ -64,6 +64,8 @@ QT_BEGIN_NAMESPACE # define Q_QUICKTEMPLATES2_PRIVATE_EXPORT #endif +Q_QUICKTEMPLATES2_PRIVATE_EXPORT void QQuickTemplates_initializeModule(); + QT_END_NAMESPACE #endif // QTQUICKTEMPLATES2GLOBAL_P_H diff --git a/src/quicktemplates2/quicktemplates2.pro b/src/quicktemplates2/quicktemplates2.pro index 8ed0151a..a3f778b2 100644 --- a/src/quicktemplates2/quicktemplates2.pro +++ b/src/quicktemplates2/quicktemplates2.pro @@ -10,5 +10,11 @@ DEFINES += QT_NO_CAST_TO_ASCII QT_NO_CAST_FROM_ASCII HEADERS += \ $$PWD/qtquicktemplates2global_p.h +SOURCES += \ + $$PWD/qtquicktemplates2global.cpp + include(quicktemplates2.pri) +qtConfig(accessibility) { + include(accessible/accessible.pri) +} load(qt_module) |