aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJ-P Nurmi <jpnurmi@theqtcompany.com>2016-01-31 16:05:25 +0100
committerJ-P Nurmi <jpnurmi@theqtcompany.com>2016-01-31 17:38:37 +0100
commit19b967506deea84a0d56375e5bcca48168a3cfc8 (patch)
treebf488dc01069b7850cceff182c2241ed13db69c6
parent8318deb165047d592523ec0b2fd10510d4953b37 (diff)
parent7fc567eda8a187e365f4c29c6e8f08440bf31218 (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
-rw-r--r--README.md22
-rw-r--r--src/controls/qquickstyleselector.cpp41
-rw-r--r--src/controls/qquickstyleselector_p.h5
-rw-r--r--src/controls/qquickstyleselector_p_p.h4
-rw-r--r--src/imports/controls/CheckBox.qml11
-rw-r--r--src/imports/controls/ComboBox.qml6
-rw-r--r--src/imports/controls/Drawer.qml3
-rw-r--r--src/imports/controls/SpinBox.qml4
-rw-r--r--src/imports/controls/TabBar.qml7
-rw-r--r--src/imports/controls/TabButton.qml2
-rw-r--r--src/imports/controls/doc/images/qtlabscontrols-tabbar.gifbin5932 -> 8590 bytes
-rw-r--r--src/imports/controls/doc/images/qtlabscontrols-tabbar.pngbin3463 -> 4725 bytes
-rw-r--r--src/imports/controls/doc/images/qtlabscontrols-tabbutton.pngbin3477 -> 4728 bytes
-rw-r--r--src/imports/controls/material/CheckBox.qml31
-rw-r--r--src/imports/controls/material/ComboBox.qml7
-rw-r--r--src/imports/controls/material/Drawer.qml3
-rw-r--r--src/imports/controls/material/RadioButton.qml7
-rw-r--r--src/imports/controls/material/Switch.qml16
-rw-r--r--src/imports/controls/plugins.qmltypes13
-rw-r--r--src/imports/controls/universal/ComboBox.qml6
-rw-r--r--src/imports/templates/plugins.qmltypes13
-rw-r--r--src/templates/qquickabstractbutton.cpp3
-rw-r--r--src/templates/qquickcombobox.cpp4
-rw-r--r--src/templates/qquickmenu.cpp9
-rw-r--r--src/templates/qquickoverlay.cpp59
-rw-r--r--src/templates/qquickpopup.cpp387
-rw-r--r--src/templates/qquickpopup_p.h32
-rw-r--r--src/templates/qquickpopup_p_p.h24
-rw-r--r--src/templates/qquickspinbox.cpp27
-rw-r--r--src/templates/qquickspinbox_p.h1
-rw-r--r--tests/auto/applicationwindow/tst_applicationwindow.cpp5
-rw-r--r--tests/manual/gifs/data/qtlabscontrols-tabbar.qml2
32 files changed, 560 insertions, 194 deletions
diff --git a/README.md b/README.md
index 03d9724f..1c67b728 100644
--- a/README.md
+++ b/README.md
@@ -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
index 0dccecb3..31db1f9e 100644
--- a/src/imports/controls/doc/images/qtlabscontrols-tabbar.gif
+++ b/src/imports/controls/doc/images/qtlabscontrols-tabbar.gif
Binary files differ
diff --git a/src/imports/controls/doc/images/qtlabscontrols-tabbar.png b/src/imports/controls/doc/images/qtlabscontrols-tabbar.png
index 100092f8..44a91d63 100644
--- a/src/imports/controls/doc/images/qtlabscontrols-tabbar.png
+++ b/src/imports/controls/doc/images/qtlabscontrols-tabbar.png
Binary files differ
diff --git a/src/imports/controls/doc/images/qtlabscontrols-tabbutton.png b/src/imports/controls/doc/images/qtlabscontrols-tabbutton.png
index ab05c1db..76d1e35c 100644
--- a/src/imports/controls/doc/images/qtlabscontrols-tabbutton.png
+++ b/src/imports/controls/doc/images/qtlabscontrols-tabbutton.png
Binary files differ
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