diff options
author | J-P Nurmi <jpnurmi@theqtcompany.com> | 2016-01-31 16:05:25 +0100 |
---|---|---|
committer | J-P Nurmi <jpnurmi@theqtcompany.com> | 2016-01-31 17:38:37 +0100 |
commit | 19b967506deea84a0d56375e5bcca48168a3cfc8 (patch) | |
tree | bf488dc01069b7850cceff182c2241ed13db69c6 | |
parent | 8318deb165047d592523ec0b2fd10510d4953b37 (diff) | |
parent | 7fc567eda8a187e365f4c29c6e8f08440bf31218 (diff) |
Merge remote-tracking branch 'origin/5.6' into dev
Conflicts:
src/templates/qquickpopup.cpp
src/templates/qquickpopup_p_p.h
src/templates/qquickspinbox_p.h
Change-Id: Ief25ad2d27410f62e90879f60499ed87359406c3
32 files changed, 560 insertions, 194 deletions
@@ -7,6 +7,14 @@ oriented Qt Quick Controls 1, the experimental Qt Labs Controls are an order of magnitude simpler, lighter and faster, and are primarily targeting embedded and mobile platforms. +Qt Labs Controls are based on a flexible template system that enables rapid +development of entire custom styles and user experiences. Qt Labs Controls +comes with a selection of built-in styles: + +- Default style - a simple and minimal all-round style that offers the maximum performance +- Material style - a style based on the Google Material Design Guidelines +- Universal style - a style based on the Microsoft Universal Design Guidelines + More information can be found in the following blog posts: - http://blog.qt.io/blog/2015/03/31/qt-quick-controls-for-embedded/ @@ -16,24 +24,24 @@ More information can be found in the following blog posts: If you have problems or questions, don't hesitate to: -- ask on the Qt Interest mailing list interest@qt-project.org +- ask on the Qt Interest mailing list http://lists.qt-project.org/mailman/listinfo/interest - ask on the Qt Forum http://forum.qt.io/category/12/qt-quick -- report issues to the Qt Bug Tracker https://bugreports.qt.io (component Qt Quick: Controls 2) +- report issues to the Qt Bug Tracker https://bugreports.qt.io (component: *Qt Quick: Controls 2*) ## Installation The MINIMUM REQUIREMENT for building this project is to use the same branch -of Qt 5. The dependencies are qtbase, qtxmlpatterns and qtdeclarative. Other -optional dependencies are qtgraphicaleffects for the Material style and -qtquickcontrols for the Qt Quick Layouts. +of Qt 5. The dependencies are *qtbase*, *qtxmlpatterns* and *qtdeclarative*. +Other optional dependencies include *qtgraphicaleffects* for the Material +style and *qtquickcontrols* for the Qt Quick Layouts. -To install the controls into your Qt directory (QTDIR/qml): +To install the controls into your Qt directory (```QTDIR/qml```): qmake make make install -If you are compiling against a system Qt on linux, you might have to use +If you are compiling against a system Qt on Linux, you might have to use ```sudo make install``` to install the project. ## Usage diff --git a/src/controls/qquickstyleselector.cpp b/src/controls/qquickstyleselector.cpp index b169ade2..21354a16 100644 --- a/src/controls/qquickstyleselector.cpp +++ b/src/controls/qquickstyleselector.cpp @@ -74,12 +74,6 @@ QQuickStyleSelector::~QQuickStyleSelector() { } -QString QQuickStyleSelector::select(const QString &filePath) const -{ - Q_D(const QQuickStyleSelector); - return select(QUrl(d->baseUrl.toString() + filePath)).toString(); -} - static bool isLocalScheme(const QString &file) { bool local = file == QLatin1String("qrc"); @@ -89,20 +83,20 @@ static bool isLocalScheme(const QString &file) return local; } -QUrl QQuickStyleSelector::select(const QUrl &filePath) const +QString QQuickStyleSelector::select(const QString &filePath) const { Q_D(const QQuickStyleSelector); - if (!isLocalScheme(filePath.scheme()) && !filePath.isLocalFile()) - return filePath; - QUrl ret(filePath); - if (isLocalScheme(filePath.scheme())) { - QString equivalentPath = QLatin1Char(':') + filePath.path(); - QString selectedPath = d->select(equivalentPath, allSelectors()); - ret.setPath(selectedPath.remove(0, 1)); - } else { - ret = QUrl::fromLocalFile(d->select(ret.toLocalFile(), allSelectors())); + QUrl url(d->baseUrl.toString() + filePath); + if (isLocalScheme(url.scheme()) || url.isLocalFile()) { + if (isLocalScheme(url.scheme())) { + QString equivalentPath = QLatin1Char(':') + url.path(); + QString selectedPath = d->select(equivalentPath); + url.setPath(selectedPath.remove(0, 1)); + } else { + url = QUrl::fromLocalFile(d->select(url.toLocalFile())); + } } - return ret; + return url.toString(); } static QString selectionHelper(const QString &path, const QString &fileName, const QStringList &selectors) @@ -131,7 +125,7 @@ static QString selectionHelper(const QString &path, const QString &fileName, con return path + fileName; } -QString QQuickStyleSelectorPrivate::select(const QString &filePath, const QStringList &allSelectors) const +QString QQuickStyleSelectorPrivate::select(const QString &filePath) const { QFileInfo fi(filePath); // If file doesn't exist, don't select @@ -139,7 +133,7 @@ QString QQuickStyleSelectorPrivate::select(const QString &filePath, const QStrin return filePath; QString ret = selectionHelper(fi.path().isEmpty() ? QString() : fi.path() + QLatin1Char('/'), - fi.fileName(), allSelectors); + fi.fileName(), allSelectors()); if (!ret.isEmpty()) return ret; @@ -158,14 +152,13 @@ void QQuickStyleSelector::setStyle(const QString &s) d->style = s; } -QStringList QQuickStyleSelector::allSelectors() const +QStringList QQuickStyleSelectorPrivate::allSelectors() const { - Q_D(const QQuickStyleSelector); QMutexLocker locker(&sharedDataMutex); - QQuickStyleSelectorPrivate::updateSelectors(); + updateSelectors(); QStringList selectors = sharedData->staticSelectors; - if (!d->style.isEmpty()) - selectors.prepend(d->style); + if (!style.isEmpty()) + selectors.prepend(style); return selectors; } diff --git a/src/controls/qquickstyleselector_p.h b/src/controls/qquickstyleselector_p.h index 64319098..2ca6ea3a 100644 --- a/src/controls/qquickstyleselector_p.h +++ b/src/controls/qquickstyleselector_p.h @@ -47,7 +47,6 @@ // #include <QtCore/qurl.h> -#include <QtCore/qstringlist.h> #include <QtCore/qscopedpointer.h> QT_BEGIN_NAMESPACE @@ -64,14 +63,10 @@ public: QString style() const; void setStyle(const QString &s); - QStringList allSelectors() const; - void setBaseUrl(const QUrl &base); QUrl baseUrl() const; private: - QUrl select(const QUrl &filePath) const; - Q_DECLARE_PRIVATE(QQuickStyleSelector) QScopedPointer<QQuickStyleSelectorPrivate> d_ptr; }; diff --git a/src/controls/qquickstyleselector_p_p.h b/src/controls/qquickstyleselector_p_p.h index b0de326b..e4df1035 100644 --- a/src/controls/qquickstyleselector_p_p.h +++ b/src/controls/qquickstyleselector_p_p.h @@ -49,6 +49,7 @@ #include <QtCore/QString> #include <QtCore/QUrl> #include <private/qobject_p.h> +#include <QtCore/qstringlist.h> #include "qquickstyleselector_p.h" @@ -67,7 +68,8 @@ public: static QStringList platformSelectors(); static void addStatics(const QStringList &); //For loading GUI statics from other Qt modules QQuickStyleSelectorPrivate(); - QString select(const QString &filePath, const QStringList &allSelectors) const; + QString select(const QString &filePath) const; + QStringList allSelectors() const; QString style; QUrl baseUrl; diff --git a/src/imports/controls/CheckBox.qml b/src/imports/controls/CheckBox.qml index 20d8ef1c..4b7af3b1 100644 --- a/src/imports/controls/CheckBox.qml +++ b/src/imports/controls/CheckBox.qml @@ -67,7 +67,16 @@ T.CheckBox { x: (parent.width - width) / 2 y: (parent.height - height) / 2 source: "qrc:/qt-project.org/imports/Qt/labs/controls/images/check.png" - visible: control.checked + visible: control.checkState === Qt.Checked + } + + Rectangle { + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + width: 16 + height: 3 + color: "#353637" + visible: control.checkState === Qt.PartiallyChecked } } //! [indicator] diff --git a/src/imports/controls/ComboBox.qml b/src/imports/controls/ComboBox.qml index fc32c6f5..30f45af3 100644 --- a/src/imports/controls/ComboBox.qml +++ b/src/imports/controls/ComboBox.qml @@ -101,7 +101,9 @@ T.ComboBox { popup: T.Popup { y: control.height - 1 implicitWidth: control.width - implicitHeight: Math.min(200, listview.contentHeight) + implicitHeight: Math.min(396, listview.contentHeight) + topMargin: 6 + bottomMargin: 6 contentItem: ListView { id: listview @@ -118,7 +120,7 @@ T.ComboBox { color: "transparent" } -// ScrollIndicator.vertical: ScrollIndicator { } + T.ScrollIndicator.vertical: ScrollIndicator { } } background: Rectangle { } diff --git a/src/imports/controls/Drawer.qml b/src/imports/controls/Drawer.qml index eb4e3e57..60abeb0c 100644 --- a/src/imports/controls/Drawer.qml +++ b/src/imports/controls/Drawer.qml @@ -35,12 +35,13 @@ ****************************************************************************/ import QtQuick 2.6 +import QtQuick.Window 2.2 import Qt.labs.templates 1.0 as T T.Drawer { id: control - parent: T.ApplicationWindow.overlay + parent: T.ApplicationWindow.overlay || Window.contentItem width: parent ? parent.width : 0 // TODO: Window.width height: parent ? parent.height : 0 // TODO: Window.height diff --git a/src/imports/controls/SpinBox.qml b/src/imports/controls/SpinBox.qml index 947ec74a..77f89206 100644 --- a/src/imports/controls/SpinBox.qml +++ b/src/imports/controls/SpinBox.qml @@ -69,8 +69,8 @@ T.SpinBox { font: control.font color: "#353637" -// selectionColor: TODO -// selectedTextColor: TODO + selectionColor: "#fddd5c" + selectedTextColor: color horizontalAlignment: Qt.AlignHCenter verticalAlignment: Qt.AlignVCenter diff --git a/src/imports/controls/TabBar.qml b/src/imports/controls/TabBar.qml index b1a9009c..f43975f2 100644 --- a/src/imports/controls/TabBar.qml +++ b/src/imports/controls/TabBar.qml @@ -50,7 +50,7 @@ T.TabBar { //! [contentItem] contentItem: ListView { implicitWidth: contentWidth - implicitHeight: contentHeight + implicitHeight: 40 model: control.contentModel currentIndex: control.currentIndex @@ -63,9 +63,6 @@ T.TabBar { //! [contentItem] //! [background] - background: Rectangle { - implicitWidth: 40 - implicitHeight: 40 - } + background: Rectangle { } //! [background] } diff --git a/src/imports/controls/TabButton.qml b/src/imports/controls/TabButton.qml index ef11e405..178a0a7f 100644 --- a/src/imports/controls/TabButton.qml +++ b/src/imports/controls/TabButton.qml @@ -48,8 +48,6 @@ T.TabButton { padding: 6 - font.pointSize: 10 - //! [label] label: Text { x: control.leftPadding diff --git a/src/imports/controls/doc/images/qtlabscontrols-tabbar.gif b/src/imports/controls/doc/images/qtlabscontrols-tabbar.gif Binary files differindex 0dccecb3..31db1f9e 100644 --- a/src/imports/controls/doc/images/qtlabscontrols-tabbar.gif +++ b/src/imports/controls/doc/images/qtlabscontrols-tabbar.gif diff --git a/src/imports/controls/doc/images/qtlabscontrols-tabbar.png b/src/imports/controls/doc/images/qtlabscontrols-tabbar.png Binary files differindex 100092f8..44a91d63 100644 --- a/src/imports/controls/doc/images/qtlabscontrols-tabbar.png +++ b/src/imports/controls/doc/images/qtlabscontrols-tabbar.png diff --git a/src/imports/controls/doc/images/qtlabscontrols-tabbutton.png b/src/imports/controls/doc/images/qtlabscontrols-tabbutton.png Binary files differindex ab05c1db..76d1e35c 100644 --- a/src/imports/controls/doc/images/qtlabscontrols-tabbutton.png +++ b/src/imports/controls/doc/images/qtlabscontrols-tabbutton.png diff --git a/src/imports/controls/material/CheckBox.qml b/src/imports/controls/material/CheckBox.qml index a4af00c7..88a8a3fc 100644 --- a/src/imports/controls/material/CheckBox.qml +++ b/src/imports/controls/material/CheckBox.qml @@ -51,8 +51,11 @@ T.CheckBox { indicator ? indicator.implicitHeight : 0) + topPadding + bottomPadding) baselineOffset: label ? label.y + label.baselineOffset : 0 - padding: 6 - spacing: 6 + spacing: 8 + topPadding: 14 + leftPadding: 8 + rightPadding: 8 + bottomPadding: 14 //! [indicator] indicator: Rectangle { @@ -62,7 +65,7 @@ T.CheckBox { implicitWidth: 20 implicitHeight: 20 color: "transparent" - border.color: control.checked ? control.Material.accentColor : control.Material.secondaryTextColor + border.color: control.checked && control.enabled ? control.Material.accentColor : control.Material.secondaryTextColor border.width: control.checked ? width / 2 : 2 radius: 2 @@ -98,15 +101,29 @@ T.CheckBox { source: "qrc:/qt-project.org/imports/Qt/labs/controls/material/images/check.png" fillMode: Image.PreserveAspectFit - scale: control.checked ? 1 : 0 + scale: control.checkState === Qt.Checked ? 1 : 0 Behavior on scale { NumberAnimation { duration: 100 } } } - states: State { - name: "checked" - when: control.checked + Rectangle { + x: (parent.width - width) / 2 + y: (parent.height - height) / 2 + width: 12 + height: 3 + visible: control.checkState === Qt.PartiallyChecked } + states: [ + State { + name: "checked" + when: control.checkState === Qt.Checked + }, + State { + name: "partiallychecked" + when: control.checkState === Qt.PartiallyChecked + } + ] + transitions: Transition { SequentialAnimation { NumberAnimation { diff --git a/src/imports/controls/material/ComboBox.qml b/src/imports/controls/material/ComboBox.qml index 5979f97a..b87034c5 100644 --- a/src/imports/controls/material/ComboBox.qml +++ b/src/imports/controls/material/ComboBox.qml @@ -109,8 +109,10 @@ T.ComboBox { popup: T.Popup { y: control.height implicitWidth: control.width - implicitHeight: Math.min(200, listview.contentHeight) + implicitHeight: Math.min(396, listview.contentHeight) transformOrigin: Item.Top + topMargin: 12 + bottomMargin: 12 enter: Transition { // grow_fade_in @@ -130,10 +132,11 @@ T.ComboBox { model: control.popup.visible ? control.delegateModel : null currentIndex: control.highlightedIndex -// ScrollIndicator.vertical: ScrollIndicator { } + T.ScrollIndicator.vertical: ScrollIndicator { } } background: Rectangle { + radius: 3 color: control.Material.dialogColor layer.enabled: control.enabled diff --git a/src/imports/controls/material/Drawer.qml b/src/imports/controls/material/Drawer.qml index cb00096d..133ea9c8 100644 --- a/src/imports/controls/material/Drawer.qml +++ b/src/imports/controls/material/Drawer.qml @@ -35,13 +35,14 @@ ****************************************************************************/ import QtQuick 2.6 +import QtQuick.Window 2.2 import Qt.labs.templates 1.0 as T import Qt.labs.controls.material 1.0 T.Drawer { id: control - parent: T.ApplicationWindow.overlay + parent: T.ApplicationWindow.overlay || Window.contentItem width: parent ? parent.width : 0 // TODO: Window.width height: parent ? parent.height : 0 // TODO: Window.height diff --git a/src/imports/controls/material/RadioButton.qml b/src/imports/controls/material/RadioButton.qml index 40761be6..893248c8 100644 --- a/src/imports/controls/material/RadioButton.qml +++ b/src/imports/controls/material/RadioButton.qml @@ -51,8 +51,11 @@ T.RadioButton { indicator ? indicator.implicitHeight : 0) + topPadding + bottomPadding) baselineOffset: label ? label.y + label.baselineOffset : 0 - padding: 6 - spacing: 6 + spacing: 8 + topPadding: 14 + leftPadding: 8 + rightPadding: 8 + bottomPadding: 14 //! [indicator] indicator: Rectangle { diff --git a/src/imports/controls/material/Switch.qml b/src/imports/controls/material/Switch.qml index b1a69286..3b9bb18f 100644 --- a/src/imports/controls/material/Switch.qml +++ b/src/imports/controls/material/Switch.qml @@ -52,20 +52,20 @@ T.Switch { indicator ? indicator.implicitHeight : 0) + topPadding + bottomPadding) baselineOffset: label ? label.y + label.baselineOffset : 0 - padding: 6 - spacing: 6 + padding: 8 + spacing: 8 //! [indicator] indicator: Item { x: text ? (control.mirrored ? control.width - width - control.rightPadding : control.leftPadding) : control.leftPadding + (control.availableWidth - width) / 2 y: control.topPadding + (control.availableHeight - height) / 2 - implicitWidth: 40 - implicitHeight: 20 + implicitWidth: 38 + implicitHeight: 32 Ripple { x: handle.x + handle.width / 2 - width / 2 y: handle.y + handle.height / 2 - height / 2 - width: handle.width - 4 + width: handle.width height: width control: control colored: control.checked @@ -74,7 +74,7 @@ T.Switch { Rectangle { width: parent.width - height: 16 + height: 14 radius: height / 2 y: parent.height / 2 - height / 2 color: control.enabled ? (control.checked ? control.Material.switchCheckedTrackColor : control.Material.switchUncheckedTrackColor) @@ -85,8 +85,8 @@ T.Switch { id: handle x: Math.max(0, Math.min(parent.width - width, control.visualPosition * parent.width - (width / 2))) y: (parent.height - height) / 2 - width: 24 - height: 24 + width: 20 + height: 20 radius: width / 2 color: control.enabled ? (control.checked ? control.Material.switchCheckedHandleColor : control.Material.switchUncheckedHandleColor) : control.Material.switchDisabledHandleColor diff --git a/src/imports/controls/plugins.qmltypes b/src/imports/controls/plugins.qmltypes index d52c6153..75805fdd 100644 --- a/src/imports/controls/plugins.qmltypes +++ b/src/imports/controls/plugins.qmltypes @@ -363,9 +363,11 @@ Module { name: "ClosePolicy" values: { "NoAutoClose": 0, - "CloseOnPressOutside": 1, - "CloseOnReleaseOutside": 2, - "CloseOnEscape": 4 + "OnPressOutside": 1, + "OnPressOutsideParent": 2, + "OnReleaseOutside": 4, + "OnReleaseOutsideParent": 8, + "OnEscape": 16 } } Enum { @@ -392,6 +394,11 @@ Module { Property { name: "contentHeight"; type: "double" } Property { name: "availableWidth"; type: "double"; isReadonly: true } Property { name: "availableHeight"; type: "double"; isReadonly: true } + Property { name: "margins"; type: "double" } + Property { name: "topMargin"; type: "double" } + Property { name: "leftMargin"; type: "double" } + Property { name: "rightMargin"; type: "double" } + Property { name: "bottomMargin"; type: "double" } Property { name: "padding"; type: "double" } Property { name: "topPadding"; type: "double" } Property { name: "leftPadding"; type: "double" } diff --git a/src/imports/controls/universal/ComboBox.qml b/src/imports/controls/universal/ComboBox.qml index 0a5701b9..f736ef96 100644 --- a/src/imports/controls/universal/ComboBox.qml +++ b/src/imports/controls/universal/ComboBox.qml @@ -111,7 +111,9 @@ T.ComboBox { //! [popup] popup: T.Popup { implicitWidth: control.width - implicitHeight: Math.min(200, listview.contentHeight) // TODO: 396 + implicitHeight: Math.min(396, listview.contentHeight) + topMargin: 8 + bottomMargin: 8 contentItem: ListView { id: listview @@ -119,7 +121,7 @@ T.ComboBox { model: control.popup.visible ? control.delegateModel : null currentIndex: control.highlightedIndex -// ScrollIndicator.vertical: ScrollIndicator { } + T.ScrollIndicator.vertical: ScrollIndicator { } } background: Rectangle { diff --git a/src/imports/templates/plugins.qmltypes b/src/imports/templates/plugins.qmltypes index 67058870..d96563a7 100644 --- a/src/imports/templates/plugins.qmltypes +++ b/src/imports/templates/plugins.qmltypes @@ -357,9 +357,11 @@ Module { name: "ClosePolicy" values: { "NoAutoClose": 0, - "CloseOnPressOutside": 1, - "CloseOnReleaseOutside": 2, - "CloseOnEscape": 4 + "OnPressOutside": 1, + "OnPressOutsideParent": 2, + "OnReleaseOutside": 4, + "OnReleaseOutsideParent": 8, + "OnEscape": 16 } } Enum { @@ -386,6 +388,11 @@ Module { Property { name: "contentHeight"; type: "double" } Property { name: "availableWidth"; type: "double"; isReadonly: true } Property { name: "availableHeight"; type: "double"; isReadonly: true } + Property { name: "margins"; type: "double" } + Property { name: "topMargin"; type: "double" } + Property { name: "leftMargin"; type: "double" } + Property { name: "rightMargin"; type: "double" } + Property { name: "bottomMargin"; type: "double" } Property { name: "padding"; type: "double" } Property { name: "topPadding"; type: "double" } Property { name: "leftPadding"; type: "double" } diff --git a/src/templates/qquickabstractbutton.cpp b/src/templates/qquickabstractbutton.cpp index ca727404..9edb4d2e 100644 --- a/src/templates/qquickabstractbutton.cpp +++ b/src/templates/qquickabstractbutton.cpp @@ -258,6 +258,9 @@ bool QQuickAbstractButton::isChecked() const void QQuickAbstractButton::setChecked(bool checked) { Q_D(QQuickAbstractButton); + if (checked && !d->checkable) + setCheckable(true); + if (d->checked != checked) { d->checked = checked; setAccessibleProperty("checked", checked); diff --git a/src/templates/qquickcombobox.cpp b/src/templates/qquickcombobox.cpp index a8c66ce6..98270a07 100644 --- a/src/templates/qquickcombobox.cpp +++ b/src/templates/qquickcombobox.cpp @@ -711,6 +711,10 @@ void QQuickComboBox::keyPressEvent(QKeyEvent *event) return; switch (event->key()) { + case Qt::Key_Escape: + if (d->isPopupVisible()) + event->accept(); + break; case Qt::Key_Space: if (!event->isAutoRepeat()) setPressed(true); diff --git a/src/templates/qquickmenu.cpp b/src/templates/qquickmenu.cpp index 7aeebd2f..742a7e35 100644 --- a/src/templates/qquickmenu.cpp +++ b/src/templates/qquickmenu.cpp @@ -489,11 +489,8 @@ void QQuickMenu::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) bool QQuickMenu::eventFilter(QObject *object, QEvent *event) { Q_D(QQuickMenu); - if (d->contentModel->count() == 0) - return false; - - if (object != d->contentItem || event->type() != QEvent::KeyRelease) - return false; + if (object != d->contentItem || event->type() != QEvent::KeyRelease || d->contentModel->count() == 0) + return QQuickPopup::eventFilter(object, event); // QTBUG-17051 // Work around the fact that ListView has no way of distinguishing between @@ -517,7 +514,7 @@ bool QQuickMenu::eventFilter(QObject *object, QEvent *event) break; } - return false; + return QQuickPopup::eventFilter(object, event); } QT_END_NAMESPACE diff --git a/src/templates/qquickoverlay.cpp b/src/templates/qquickoverlay.cpp index 23895d9c..388a5960 100644 --- a/src/templates/qquickoverlay.cpp +++ b/src/templates/qquickoverlay.cpp @@ -35,7 +35,7 @@ ****************************************************************************/ #include "qquickoverlay_p.h" -#include "qquickpopup_p.h" +#include "qquickpopup_p_p.h" #include "qquickdrawer_p.h" #include <QtQml/qqmlinfo.h> #include <QtQml/qqmlproperty.h> @@ -52,13 +52,12 @@ public: void popupAboutToShow(); void popupAboutToHide(); - void closePopup(QQuickPopup *popup, QMouseEvent *event); void drawerPositionChange(); void resizeBackground(); QQuickItem *background; QVector<QQuickDrawer *> drawers; - QHash<QQuickItem *, QQuickPopup *> popups; + QVector<QQuickPopup *> popups; int modalPopups; }; @@ -90,30 +89,6 @@ void QQuickOverlayPrivate::popupAboutToHide() QQmlProperty::write(background, QStringLiteral("opacity"), 0.0); } -void QQuickOverlayPrivate::closePopup(QQuickPopup *popup, QMouseEvent *event) -{ - Q_Q(QQuickOverlay); - const bool isPress = event->type() == QEvent::MouseButtonPress; - const bool onOutside = popup->closePolicy().testFlag(isPress ? QQuickPopup::OnPressOutside : QQuickPopup::OnReleaseOutside); - const bool onOutsideParent = popup->closePolicy().testFlag(isPress ? QQuickPopup::OnPressOutsideParent : QQuickPopup::OnReleaseOutsideParent); - if (onOutside || onOutsideParent) { - QQuickItem *popupItem = popup->popupItem(); - QQuickItem *parentItem = popup->parentItem(); - - if (onOutside && onOutsideParent) { - if (!popupItem->contains(q->mapToItem(popupItem, event->pos())) && - (!parentItem || !parentItem->contains(q->mapToItem(parentItem, event->pos())))) - popup->close(); - } else if (onOutside) { - if (!popupItem->contains(q->mapToItem(popupItem, event->pos()))) - popup->close(); - } else if (onOutsideParent) { - if (!parentItem || !parentItem->contains(q->mapToItem(parentItem, event->pos()))) - popup->close(); - } - } -} - void QQuickOverlayPrivate::drawerPositionChange() { Q_Q(QQuickOverlay); @@ -197,27 +172,19 @@ void QQuickOverlay::itemChange(ItemChange change, const ItemChangeData &data) return; if (change == ItemChildAddedChange) { - if (QQuickPopup *prevPopup = d->popups.value(data.item)) { - qmlInfo(popup).nospace() << "Popup is sharing item " << data.item << " with " << prevPopup - << ". This is not supported and strange things are about to happen."; - return; - } - - d->popups.insert(data.item, popup); + d->popups.append(popup); if (popup->isModal()) ++d->modalPopups; QObjectPrivate::connect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); QObjectPrivate::connect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); } else if (change == ItemChildRemovedChange) { - Q_ASSERT(popup == d->popups.value(data.item)); + d->popups.removeOne(popup); + if (popup->isModal()) + --d->modalPopups; QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToShow, d, &QQuickOverlayPrivate::popupAboutToShow); QObjectPrivate::disconnect(popup, &QQuickPopup::aboutToHide, d, &QQuickOverlayPrivate::popupAboutToHide); - - if (popup->isModal()) - --d->modalPopups; - d->popups.remove(data.item); } } @@ -247,8 +214,10 @@ void QQuickOverlay::mousePressEvent(QMouseEvent *event) event->setAccepted(d->modalPopups > 0); emit pressed(); - foreach (QQuickPopup *popup, d->popups) - d->closePopup(popup, event); + for (int i = d->popups.count() - 1; i >= 0; --i) { + if (QQuickPopupPrivate::get(d->popups.at(i))->tryClose(this, event)) + break; + } } void QQuickOverlay::mouseMoveEvent(QMouseEvent *event) @@ -263,8 +232,10 @@ void QQuickOverlay::mouseReleaseEvent(QMouseEvent *event) event->setAccepted(d->modalPopups > 0); emit released(); - foreach (QQuickPopup *popup, d->popups) - d->closePopup(popup, event); + for (int i = d->popups.count() - 1; i >= 0; --i) { + if (QQuickPopupPrivate::get(d->popups.at(i))->tryClose(this, event)) + break; + } } void QQuickOverlay::wheelEvent(QWheelEvent *event) @@ -292,7 +263,7 @@ bool QQuickOverlay::childMouseEventFilter(QQuickItem *item, QEvent *event) if (popupItem == item) break; - QQuickPopup *popup = d->popups.value(popupItem); + QQuickPopup *popup = qobject_cast<QQuickPopup *>(popupItem->parent()); if (popup) { QQuickPopup::ClosePolicy policy = popup->closePolicy(); if (policy.testFlag(QQuickPopup::OnPressOutside) || policy.testFlag(QQuickPopup::OnPressOutsideParent)) diff --git a/src/templates/qquickpopup.cpp b/src/templates/qquickpopup.cpp index ea74743a..8f9a04cb 100644 --- a/src/templates/qquickpopup.cpp +++ b/src/templates/qquickpopup.cpp @@ -71,10 +71,19 @@ QQuickPopupPrivate::QQuickPopupPrivate() : QObjectPrivate() , focus(false) , modal(false) + , hasTopMargin(false) + , hasLeftMargin(false) + , hasRightMargin(false) + , hasBottomMargin(false) , hasTopPadding(false) , hasLeftPadding(false) , hasRightPadding(false) , hasBottomPadding(false) + , margins(0) + , topMargin(0) + , leftMargin(0) + , rightMargin(0) + , bottomMargin(0) , padding(0) , topPadding(0) , leftPadding(0) @@ -86,7 +95,6 @@ QQuickPopupPrivate::QQuickPopupPrivate() , parentItem(nullptr) , background(nullptr) , contentItem(nullptr) - , overlay(nullptr) , enter(nullptr) , exit(nullptr) , popupItem(nullptr) @@ -99,10 +107,32 @@ void QQuickPopupPrivate::init() { Q_Q(QQuickPopup); popupItem = new QQuickPopupItem(q); - popupItem->setParent(q); q->setParentItem(qobject_cast<QQuickItem *>(parent)); } +bool QQuickPopupPrivate::tryClose(QQuickItem *item, QMouseEvent *event) +{ + Q_Q(QQuickPopup); + const bool isPress = event->type() == QEvent::MouseButtonPress; + const bool onOutside = closePolicy.testFlag(isPress ? QQuickPopup::OnPressOutside : QQuickPopup::OnReleaseOutside); + const bool onOutsideParent = closePolicy.testFlag(isPress ? QQuickPopup::OnPressOutsideParent : QQuickPopup::OnReleaseOutsideParent); + if (onOutside || onOutsideParent) { + if (onOutsideParent) { + if (!popupItem->contains(item->mapToItem(popupItem, event->pos())) && + (!parentItem || !parentItem->contains(item->mapToItem(parentItem, event->pos())))) { + q->close(); + return true; + } + } else if (onOutside) { + if (!popupItem->contains(item->mapToItem(popupItem, event->pos()))) { + q->close(); + return true; + } + } + } + return false; +} + void QQuickPopupPrivate::finalizeEnterTransition() { if (focus) @@ -111,11 +141,9 @@ void QQuickPopupPrivate::finalizeEnterTransition() void QQuickPopupPrivate::finalizeExitTransition() { - Q_Q(QQuickPopup); - overlay = nullptr; positioner.setParentItem(nullptr); popupItem->setParentItem(nullptr); - emit q->visibleChanged(); + popupItem->setVisible(false); } void QQuickPopupPrivate::resizeBackground() @@ -143,6 +171,64 @@ void QQuickPopupPrivate::resizeContent() } } +QMarginsF QQuickPopupPrivate::getMargins() const +{ + Q_Q(const QQuickPopup); + return QMarginsF(q->leftMargin(), q->topMargin(), q->rightMargin(), q->bottomMargin()); +} + +void QQuickPopupPrivate::setTopMargin(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldMargin = q->topMargin(); + topMargin = value; + hasTopMargin = !reset; + if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) { + emit q->topMarginChanged(); + q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin), + QMarginsF(leftMargin, oldMargin, rightMargin, bottomMargin)); + } +} + +void QQuickPopupPrivate::setLeftMargin(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldMargin = q->leftMargin(); + leftMargin = value; + hasLeftMargin = !reset; + if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) { + emit q->leftMarginChanged(); + q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin), + QMarginsF(oldMargin, topMargin, rightMargin, bottomMargin)); + } +} + +void QQuickPopupPrivate::setRightMargin(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldMargin = q->rightMargin(); + rightMargin = value; + hasRightMargin = !reset; + if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) { + emit q->rightMarginChanged(); + q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin), + QMarginsF(leftMargin, topMargin, oldMargin, bottomMargin)); + } +} + +void QQuickPopupPrivate::setBottomMargin(qreal value, bool reset) +{ + Q_Q(QQuickPopup); + qreal oldMargin = q->bottomMargin(); + bottomMargin = value; + hasBottomMargin = !reset; + if ((!reset && !qFuzzyCompare(oldMargin, value)) || (reset && !qFuzzyCompare(oldMargin, margins))) { + emit q->bottomMarginChanged(); + q->marginsChange(QMarginsF(leftMargin, topMargin, rightMargin, bottomMargin), + QMarginsF(leftMargin, topMargin, rightMargin, oldMargin)); + } +} + void QQuickPopupPrivate::setTopPadding(qreal value, bool reset) { Q_Q(QQuickPopup); @@ -214,6 +300,7 @@ public: QQuickPopupItemPrivate::QQuickPopupItemPrivate(QQuickPopup *popup) : popup(popup) { + isTabFence = true; } void QQuickPopupItemPrivate::implicitWidthChanged() @@ -229,6 +316,9 @@ void QQuickPopupItemPrivate::implicitHeightChanged() QQuickPopupItem::QQuickPopupItem(QQuickPopup *popup) : QQuickItem(*(new QQuickPopupItemPrivate(popup))) { + setParent(popup); + setVisible(false); + setFlag(ItemIsFocusScope); setAcceptedMouseButtons(Qt::AllButtons); } @@ -298,6 +388,19 @@ void QQuickPopupItem::geometryChanged(const QRectF &newGeometry, const QRectF &o d->popup->geometryChanged(newGeometry, oldGeometry); } +void QQuickPopupItem::itemChange(ItemChange change, const ItemChangeData &data) +{ + Q_D(QQuickPopupItem); + QQuickItem::itemChange(change, data); + switch (change) { + case ItemVisibleHasChanged: + emit d->popup->visibleChanged(); + break; + default: + break; + } +} + QQuickPopupPositioner::QQuickPopupPositioner(QQuickPopupPrivate *popup) : m_x(0), m_y(0), @@ -323,7 +426,8 @@ void QQuickPopupPositioner::setX(qreal x) { if (m_x != x) { m_x = x; - repositionPopup(); + if (m_popup->popupItem->isVisible()) + repositionPopup(); } } @@ -336,7 +440,8 @@ void QQuickPopupPositioner::setY(qreal y) { if (m_y != y) { m_y = y; - repositionPopup(); + if (m_popup->popupItem->isVisible()) + repositionPopup(); } } @@ -363,12 +468,14 @@ void QQuickPopupPositioner::setParentItem(QQuickItem *parent) QQuickItemPrivate::get(parent)->addItemChangeListener(this, ItemChangeTypes); addAncestorListeners(parent->parentItem()); - repositionPopup(); + if (m_popup->popupItem->isVisible()) + repositionPopup(); } void QQuickPopupPositioner::itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &) { - repositionPopup(); + if (m_popup->popupItem->isVisible()) + repositionPopup(); } void QQuickPopupPositioner::itemParentChanged(QQuickItem *, QQuickItem *parent) @@ -393,22 +500,44 @@ void QQuickPopupPositioner::itemDestroyed(QQuickItem *item) void QQuickPopupPositioner::repositionPopup() { - QRectF rect(m_x, m_y, m_popup->popupItem->width(), m_popup->popupItem->height()); + const qreal w = m_popup->popupItem->width(); + const qreal h = m_popup->popupItem->height(); + const qreal iw = m_popup->popupItem->implicitWidth(); + const qreal ih = m_popup->popupItem->implicitHeight(); + + QRectF rect(m_x, m_y, iw > 0 ? iw : w, ih > 0 ? ih : h); if (m_parentItem) { rect = m_parentItem->mapRectToScene(rect); QQuickWindow *window = m_parentItem->window(); if (window) { - if (rect.top() < 0 || rect.bottom() > window->height()) { - // if the popup doesn't fit on the screen, try flipping it around (below <-> above) - QRectF flipped = m_parentItem->mapRectToScene(QRectF(m_x, m_parentItem->height() - m_y - rect.height(), rect.width(), rect.height())); - if (flipped.y() >= 0 && flipped.bottom() < window->height()) + const QRectF bounds = QRectF(0, 0, window->width(), window->height()).marginsRemoved(m_popup->getMargins()); + if (rect.top() < bounds.top() || rect.bottom() > bounds.bottom()) { + // if the popup doesn't fit inside the window, try flipping it around (below <-> above) + const QRectF flipped = m_parentItem->mapRectToScene(QRectF(m_x, m_parentItem->height() - m_y - rect.height(), rect.width(), rect.height())); + if (flipped.top() >= bounds.top() && flipped.bottom() < bounds.bottom()) { rect = flipped; + } else if (ih > 0) { + // neither the flipped around geometry fits inside the window, choose + // whichever side (above vs. below) fits larger part of the popup + const QRectF primary = rect.intersected(bounds); + const QRectF secondary = flipped.intersected(bounds); + + if (primary.height() > secondary.height()) { + rect.setY(primary.y()); + rect.setHeight(primary.height()); + } else { + rect.setY(secondary.y()); + rect.setHeight(secondary.height()); + } + } } } } m_popup->popupItem->setPosition(rect.topLeft()); + if (ih > 0) + m_popup->popupItem->setHeight(rect.height()); } void QQuickPopupPositioner::removeAncestorListeners(QQuickItem *item) @@ -514,24 +643,12 @@ QQuickPopup::~QQuickPopup() void QQuickPopup::open() { Q_D(QQuickPopup); - if (d->overlay) { - // popup already open + if (d->popupItem->isVisible()) return; - } QQuickWindow *window = nullptr; - QObject *p = parent(); - while (p && !window) { - if (QQuickItem *item = qobject_cast<QQuickItem *>(p)) { - window = item->window(); - if (!window) - p = item->parentItem(); - } else { - window = qobject_cast<QQuickWindow *>(p); - if (!window) - p = p->parent(); - } - } + if (d->parentItem) + window = d->parentItem->window(); if (!window) { qmlInfo(this) << "cannot find any window to open popup in."; return; @@ -539,17 +656,17 @@ void QQuickPopup::open() QQuickApplicationWindow *applicationWindow = qobject_cast<QQuickApplicationWindow*>(window); if (!applicationWindow) { - // FIXME Maybe try to open it in that window somehow - qmlInfo(this) << "is not in an ApplicationWindow."; - return; + window->installEventFilter(this); + d->popupItem->setZ(10001); // DefaultWindowDecoration+1 + d->popupItem->setParentItem(window->contentItem()); + } else { + d->popupItem->setParentItem(applicationWindow->overlay()); } - d->overlay = static_cast<QQuickOverlay *>(applicationWindow->overlay()); - d->popupItem->setParentItem(d->overlay); - d->positioner.setParentItem(d->parentItem); emit aboutToShow(); + d->popupItem->setVisible(true); + d->positioner.setParentItem(d->parentItem); d->transitionManager.transitionEnter(); - emit visibleChanged(); } /*! @@ -560,9 +677,14 @@ void QQuickPopup::open() void QQuickPopup::close() { Q_D(QQuickPopup); - if (!d->overlay) { - // popup already closed + if (!d->popupItem->isVisible()) return; + + if (d->parentItem) { + QQuickWindow *window = d->parentItem->window(); + if (!qobject_cast<QQuickApplicationWindow *>(window)) { + window->removeEventFilter(this); + } } d->popupItem->setFocus(false); @@ -757,6 +879,152 @@ qreal QQuickPopup::availableHeight() const } /*! + \qmlproperty real Qt.labs.controls::Popup::margins + + This property holds the default margins around the popup. + + \sa topMargin, leftMargin, rightMargin, bottomMargin +*/ +qreal QQuickPopup::margins() const +{ + Q_D(const QQuickPopup); + return d->margins; +} + +void QQuickPopup::setMargins(qreal margins) +{ + Q_D(QQuickPopup); + if (qFuzzyCompare(d->margins, margins)) + return; + QMarginsF oldMargins(leftMargin(), topMargin(), rightMargin(), bottomMargin()); + d->margins = margins; + emit marginsChanged(); + QMarginsF newMargins(leftMargin(), topMargin(), rightMargin(), bottomMargin()); + if (!qFuzzyCompare(newMargins.top(), oldMargins.top())) + emit topMarginChanged(); + if (!qFuzzyCompare(newMargins.left(), oldMargins.left())) + emit leftMarginChanged(); + if (!qFuzzyCompare(newMargins.right(), oldMargins.right())) + emit rightMarginChanged(); + if (!qFuzzyCompare(newMargins.bottom(), oldMargins.bottom())) + emit bottomMarginChanged(); + marginsChange(newMargins, oldMargins); +} + +void QQuickPopup::resetMargins() +{ + setMargins(0); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::topMargin + + This property holds the top margin around the popup. + + \sa margin, bottomMargin +*/ +qreal QQuickPopup::topMargin() const +{ + Q_D(const QQuickPopup); + if (d->hasTopMargin) + return d->topMargin; + return d->margins; +} + +void QQuickPopup::setTopMargin(qreal margin) +{ + Q_D(QQuickPopup); + d->setTopMargin(margin); +} + +void QQuickPopup::resetTopMargin() +{ + Q_D(QQuickPopup); + d->setTopMargin(0, true); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::leftMargin + + This property holds the left margin around the popup. + + \sa margin, rightMargin +*/ +qreal QQuickPopup::leftMargin() const +{ + Q_D(const QQuickPopup); + if (d->hasLeftMargin) + return d->leftMargin; + return d->margins; +} + +void QQuickPopup::setLeftMargin(qreal margin) +{ + Q_D(QQuickPopup); + d->setLeftMargin(margin); +} + +void QQuickPopup::resetLeftMargin() +{ + Q_D(QQuickPopup); + d->setLeftMargin(0, true); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::rightMargin + + This property holds the right margin around the popup. + + \sa margin, leftMargin +*/ +qreal QQuickPopup::rightMargin() const +{ + Q_D(const QQuickPopup); + if (d->hasRightMargin) + return d->rightMargin; + return d->margins; +} + +void QQuickPopup::setRightMargin(qreal margin) +{ + Q_D(QQuickPopup); + d->setRightMargin(margin); +} + +void QQuickPopup::resetRightMargin() +{ + Q_D(QQuickPopup); + d->setRightMargin(0, true); +} + +/*! + \qmlproperty real Qt.labs.controls::Popup::bottomMargin + + This property holds the bottom margin around the popup. + + \sa margin, topMargin +*/ +qreal QQuickPopup::bottomMargin() const +{ + Q_D(const QQuickPopup); + if (d->hasBottomMargin) + return d->bottomMargin; + return d->margins; +} + +void QQuickPopup::setBottomMargin(qreal margin) +{ + Q_D(QQuickPopup); + d->setBottomMargin(margin); +} + +void QQuickPopup::resetBottomMargin() +{ + Q_D(QQuickPopup); + d->setBottomMargin(0, true); +} + +/*! \qmlproperty real Qt.labs.controls::Popup::padding This property holds the default padding. @@ -985,18 +1253,12 @@ QQuickItem *QQuickPopup::contentItem() const void QQuickPopup::setContentItem(QQuickItem *item) { Q_D(QQuickPopup); - if (d->overlay) { - // FIXME qmlInfo needs to know about QQuickItem and/or QObject - static_cast<QDebug>(qmlInfo(this) << "cannot set content item") << item << "while Popup is visible."; - return; - } if (d->contentItem != item) { contentItemChange(item, d->contentItem); delete d->contentItem; d->contentItem = item; if (item) { item->setParentItem(d->popupItem); - QQuickItemPrivate::get(item)->isTabFence = true; if (isComponentComplete()) d->resizeContent(); } @@ -1087,7 +1349,7 @@ void QQuickPopup::setModal(bool modal) bool QQuickPopup::isVisible() const { Q_D(const QQuickPopup); - return d->overlay != nullptr /*&& !d->transitionManager.isRunning()*/; + return d->popupItem->isVisible(); } void QQuickPopup::setVisible(bool visible) @@ -1214,6 +1476,32 @@ bool QQuickPopup::isComponentComplete() const return d->complete; } +bool QQuickPopup::eventFilter(QObject *object, QEvent *event) +{ + Q_D(QQuickPopup); + Q_UNUSED(object); + switch (event->type()) { + case QEvent::MouseButtonPress: + case QEvent::MouseButtonRelease: + if (d->modal) + event->setAccepted(true); + if (QQuickWindow *window = qobject_cast<QQuickWindow *>(object)) { + if (d->tryClose(window->contentItem(), static_cast<QMouseEvent *>(event))) + return true; + } + return false; + case QEvent::KeyPress: + case QEvent::KeyRelease: + case QEvent::MouseMove: + case QEvent::Wheel: + if (d->modal) + event->setAccepted(true); + return false; + default: + return false; + } +} + void QQuickPopup::focusInEvent(QFocusEvent *event) { event->accept(); @@ -1281,6 +1569,7 @@ void QQuickPopup::geometryChanged(const QRectF &newGeometry, const QRectF &oldGe Q_D(QQuickPopup); d->resizeBackground(); d->resizeContent(); + d->positioner.repositionPopup(); if (!qFuzzyCompare(newGeometry.width(), oldGeometry.width())) { emit widthChanged(); emit availableWidthChanged(); @@ -1291,6 +1580,14 @@ void QQuickPopup::geometryChanged(const QRectF &newGeometry, const QRectF &oldGe } } +void QQuickPopup::marginsChange(const QMarginsF &newMargins, const QMarginsF &oldMargins) +{ + Q_D(QQuickPopup); + Q_UNUSED(newMargins); + Q_UNUSED(oldMargins); + d->positioner.repositionPopup(); +} + void QQuickPopup::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding) { Q_D(QQuickPopup); diff --git a/src/templates/qquickpopup_p.h b/src/templates/qquickpopup_p.h index 233978c8..ee08c08a 100644 --- a/src/templates/qquickpopup_p.h +++ b/src/templates/qquickpopup_p.h @@ -77,6 +77,11 @@ class Q_LABSTEMPLATES_EXPORT QQuickPopup : public QObject, public QQmlParserStat Q_PROPERTY(qreal contentHeight READ contentHeight WRITE setContentHeight NOTIFY contentHeightChanged FINAL) Q_PROPERTY(qreal availableWidth READ availableWidth NOTIFY availableWidthChanged FINAL) Q_PROPERTY(qreal availableHeight READ availableHeight NOTIFY availableHeightChanged FINAL) + Q_PROPERTY(qreal margins READ margins WRITE setMargins RESET resetMargins NOTIFY marginsChanged FINAL) + Q_PROPERTY(qreal topMargin READ topMargin WRITE setTopMargin RESET resetTopMargin NOTIFY topMarginChanged FINAL) + Q_PROPERTY(qreal leftMargin READ leftMargin WRITE setLeftMargin RESET resetLeftMargin NOTIFY leftMarginChanged FINAL) + Q_PROPERTY(qreal rightMargin READ rightMargin WRITE setRightMargin RESET resetRightMargin NOTIFY rightMarginChanged FINAL) + Q_PROPERTY(qreal bottomMargin READ bottomMargin WRITE setBottomMargin RESET resetBottomMargin NOTIFY bottomMarginChanged FINAL) Q_PROPERTY(qreal padding READ padding WRITE setPadding RESET resetPadding NOTIFY paddingChanged FINAL) Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged FINAL) Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged FINAL) @@ -129,6 +134,26 @@ public: qreal availableWidth() const; qreal availableHeight() const; + qreal margins() const; + void setMargins(qreal margins); + void resetMargins(); + + qreal topMargin() const; + void setTopMargin(qreal margin); + void resetTopMargin(); + + qreal leftMargin() const; + void setLeftMargin(qreal margin); + void resetLeftMargin(); + + qreal rightMargin() const; + void setRightMargin(qreal margin); + void resetRightMargin(); + + qreal bottomMargin() const; + void setBottomMargin(qreal margin); + void resetBottomMargin(); + qreal padding() const; void setPadding(qreal padding); void resetPadding(); @@ -218,6 +243,11 @@ Q_SIGNALS: void contentHeightChanged(); void availableWidthChanged(); void availableHeightChanged(); + void marginsChanged(); + void topMarginChanged(); + void leftMarginChanged(); + void rightMarginChanged(); + void bottomMarginChanged(); void paddingChanged(); void topPaddingChanged(); void leftPaddingChanged(); @@ -244,6 +274,7 @@ protected: void componentComplete() override; bool isComponentComplete() const; + bool eventFilter(QObject *object, QEvent *event) override; virtual void focusInEvent(QFocusEvent *event); virtual void focusOutEvent(QFocusEvent *event); virtual void keyPressEvent(QKeyEvent *event); @@ -257,6 +288,7 @@ protected: virtual void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem); virtual void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry); + virtual void marginsChange(const QMarginsF &newMargins, const QMarginsF &oldMargins); virtual void paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding); private: diff --git a/src/templates/qquickpopup_p_p.h b/src/templates/qquickpopup_p_p.h index 5817cbd5..c576071b 100644 --- a/src/templates/qquickpopup_p_p.h +++ b/src/templates/qquickpopup_p_p.h @@ -60,7 +60,6 @@ QT_BEGIN_NAMESPACE class QQuickTransition; class QQuickTransitionManager; class QQuickPopup; -class QQuickOverlay; class QQuickPopupPrivate; class QQuickPopupItemPrivate; @@ -104,6 +103,7 @@ protected: void wheelEvent(QWheelEvent *event) override; void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override; + void itemChange(ItemChange change, const ItemChangeData &data) override; private: Q_DECLARE_PRIVATE(QQuickPopupItem) @@ -124,6 +124,8 @@ public: QQuickItem *parentItem() const; void setParentItem(QQuickItem *parent); + void repositionPopup(); + protected: void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &); void itemParentChanged(QQuickItem *, QQuickItem *parent); @@ -131,8 +133,6 @@ protected: void itemDestroyed(QQuickItem *item); private: - void repositionPopup(); - void removeAncestorListeners(QQuickItem *item); void addAncestorListeners(QQuickItem *item); @@ -157,6 +157,7 @@ public: } void init(); + bool tryClose(QQuickItem *item, QMouseEvent *event); void finalizeEnterTransition(); void finalizeExitTransition(); @@ -164,6 +165,13 @@ public: void resizeBackground(); void resizeContent(); + QMarginsF getMargins() const; + + void setTopMargin(qreal value, bool reset = false); + void setLeftMargin(qreal value, bool reset = false); + void setRightMargin(qreal value, bool reset = false); + void setBottomMargin(qreal value, bool reset = false); + void setTopPadding(qreal value, bool reset = false); void setLeftPadding(qreal value, bool reset = false); void setRightPadding(qreal value, bool reset = false); @@ -172,10 +180,19 @@ public: bool focus; bool modal; bool complete; + bool hasTopMargin; + bool hasLeftMargin; + bool hasRightMargin; + bool hasBottomMargin; bool hasTopPadding; bool hasLeftPadding; bool hasRightPadding; bool hasBottomPadding; + qreal margins; + qreal topMargin; + qreal leftMargin; + qreal rightMargin; + qreal bottomMargin; qreal padding; qreal topPadding; qreal leftPadding; @@ -187,7 +204,6 @@ public: QQuickItem *parentItem; QQuickItem *background; QQuickItem *contentItem; - QQuickOverlay *overlay; QQuickTransition *enter; QQuickTransition *exit; QQuickPopupItem *popupItem; diff --git a/src/templates/qquickspinbox.cpp b/src/templates/qquickspinbox.cpp index 31368a1a..1144e3ad 100644 --- a/src/templates/qquickspinbox.cpp +++ b/src/templates/qquickspinbox.cpp @@ -116,8 +116,8 @@ public: QQuickSpinButton *up; QQuickSpinButton *down; QValidator *validator; - QJSValue textFromValue; - QJSValue valueFromText; + mutable QJSValue textFromValue; + mutable QJSValue valueFromText; }; int QQuickSpinBoxPrivate::boundValue(int value) const @@ -384,6 +384,11 @@ void QQuickSpinBox::setValidator(QValidator *validator) QJSValue QQuickSpinBox::textFromValue() const { Q_D(const QQuickSpinBox); + if (!d->textFromValue.isCallable()) { + QQmlEngine *engine = qmlEngine(this); + if (engine) + d->textFromValue = engine->evaluate(QStringLiteral("function(value, locale) { return Number(value).toLocaleString(locale, 'f', 0); }")); + } return d->textFromValue; } @@ -420,6 +425,11 @@ void QQuickSpinBox::setTextFromValue(const QJSValue &callback) QJSValue QQuickSpinBox::valueFromText() const { Q_D(const QQuickSpinBox); + if (!d->valueFromText.isCallable()) { + QQmlEngine *engine = qmlEngine(this); + if (engine) + d->valueFromText = engine->evaluate(QStringLiteral("function(text, locale) { return Number.fromLocaleString(locale, text); }")); + } return d->valueFromText; } @@ -587,19 +597,6 @@ void QQuickSpinBox::timerEvent(QTimerEvent *event) } } -void QQuickSpinBox::componentComplete() -{ - Q_D(QQuickSpinBox); - QQuickControl::componentComplete(); - QQmlEngine *engine = qmlEngine(this); - if (engine) { - if (!d->textFromValue.isCallable()) - setTextFromValue(engine->evaluate(QStringLiteral("function(value, locale) { return Number(value).toLocaleString(locale, 'f', 0); }"))); - if (!d->valueFromText.isCallable()) - setValueFromText(engine->evaluate(QStringLiteral("function(text, locale) { return Number.fromLocaleString(locale, text); }"))); - } -} - void QQuickSpinBox::itemChange(ItemChange change, const ItemChangeData &value) { Q_D(QQuickSpinBox); diff --git a/src/templates/qquickspinbox_p.h b/src/templates/qquickspinbox_p.h index 5d05c25b..831c73c2 100644 --- a/src/templates/qquickspinbox_p.h +++ b/src/templates/qquickspinbox_p.h @@ -121,7 +121,6 @@ protected: void mouseUngrabEvent() override; void timerEvent(QTimerEvent *event) override; - void componentComplete() override; void itemChange(ItemChange change, const ItemChangeData &value) override; void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override; diff --git a/tests/auto/applicationwindow/tst_applicationwindow.cpp b/tests/auto/applicationwindow/tst_applicationwindow.cpp index 4b392e99..f78d1f66 100644 --- a/tests/auto/applicationwindow/tst_applicationwindow.cpp +++ b/tests/auto/applicationwindow/tst_applicationwindow.cpp @@ -437,6 +437,11 @@ void tst_applicationwindow::attachedProperties() QVERIFY(!childItem->property("attached_header").value<QQuickItem *>()); QVERIFY(!childItem->property("attached_footer").value<QQuickItem *>()); QVERIFY(!childItem->property("attached_overlay").value<QQuickItem *>()); + + // ### A temporary workaround to unblock the CI until the crash caused + // by https://codereview.qt-project.org/#/c/108517/ has been fixed... + window->hide(); + qApp->processEvents(); } void tst_applicationwindow::font() diff --git a/tests/manual/gifs/data/qtlabscontrols-tabbar.qml b/tests/manual/gifs/data/qtlabscontrols-tabbar.qml index 55bf5e27..8ca14721 100644 --- a/tests/manual/gifs/data/qtlabscontrols-tabbar.qml +++ b/tests/manual/gifs/data/qtlabscontrols-tabbar.qml @@ -43,7 +43,7 @@ import QtQuick.Window 2.0 import Qt.labs.controls 1.0 Window { - width: 200 + width: 300 height: tabBar.height visible: true |