aboutsummaryrefslogtreecommitdiffstats
path: root/src/quicktemplates2
diff options
context:
space:
mode:
Diffstat (limited to 'src/quicktemplates2')
-rw-r--r--src/quicktemplates2/qquickabstractbutton.cpp4
-rw-r--r--src/quicktemplates2/qquickabstractbutton_p_p.h2
-rw-r--r--src/quicktemplates2/qquickapplicationwindow.cpp25
-rw-r--r--src/quicktemplates2/qquickbuttongroup.cpp38
-rw-r--r--src/quicktemplates2/qquickbuttongroup_p.h1
-rw-r--r--src/quicktemplates2/qquickcombobox.cpp35
-rw-r--r--src/quicktemplates2/qquickcombobox_p.h5
-rw-r--r--src/quicktemplates2/qquickcontainer.cpp32
-rw-r--r--src/quicktemplates2/qquickcontainer_p.h2
-rw-r--r--src/quicktemplates2/qquickdialog.cpp386
-rw-r--r--src/quicktemplates2/qquickdialog_p.h110
-rw-r--r--src/quicktemplates2/qquickdialog_p_p.h81
-rw-r--r--src/quicktemplates2/qquickdialogbuttonbox.cpp672
-rw-r--r--src/quicktemplates2/qquickdialogbuttonbox_p.h155
-rw-r--r--src/quicktemplates2/qquickdialogbuttonbox_p_p.h107
-rw-r--r--src/quicktemplates2/qquickdrawer.cpp2
-rw-r--r--src/quicktemplates2/qquickmenu.cpp2
-rw-r--r--src/quicktemplates2/qquickmenu_p_p.h2
-rw-r--r--src/quicktemplates2/qquickmenuseparator.cpp80
-rw-r--r--src/quicktemplates2/qquickmenuseparator_p.h75
-rw-r--r--src/quicktemplates2/qquickpage.cpp138
-rw-r--r--src/quicktemplates2/qquickpagelayout.cpp188
-rw-r--r--src/quicktemplates2/qquickpagelayout_p_p.h86
-rw-r--r--src/quicktemplates2/qquickpopup.cpp62
-rw-r--r--src/quicktemplates2/qquickpopup_p.h10
-rw-r--r--src/quicktemplates2/qquickpopup_p_p.h2
-rw-r--r--src/quicktemplates2/qquickpresshandler.cpp42
-rw-r--r--src/quicktemplates2/qquickpresshandler_p_p.h2
-rw-r--r--src/quicktemplates2/qquickrangeslider.cpp63
-rw-r--r--src/quicktemplates2/qquickrangeslider_p.h8
-rw-r--r--src/quicktemplates2/qquickscrollbar.cpp12
-rw-r--r--src/quicktemplates2/qquickscrollindicator.cpp12
-rw-r--r--src/quicktemplates2/qquickslider.cpp36
-rw-r--r--src/quicktemplates2/qquickslider_p.h2
-rw-r--r--src/quicktemplates2/qquickspinbox.cpp59
-rw-r--r--src/quicktemplates2/qquickspinbox_p.h8
-rw-r--r--src/quicktemplates2/qquickstackview.cpp128
-rw-r--r--src/quicktemplates2/qquickstackview_p.cpp259
-rw-r--r--src/quicktemplates2/qquickstackview_p.h13
-rw-r--r--src/quicktemplates2/qquickstackview_p_p.h26
-rw-r--r--src/quicktemplates2/qquickswipedelegate.cpp238
-rw-r--r--src/quicktemplates2/qquickswipedelegate_p.h28
-rw-r--r--src/quicktemplates2/qquickswipeview.cpp155
-rw-r--r--src/quicktemplates2/qquickswipeview_p.h15
-rw-r--r--src/quicktemplates2/qquicktextarea.cpp111
-rw-r--r--src/quicktemplates2/qquicktextarea_p.h14
-rw-r--r--src/quicktemplates2/qquicktextarea_p_p.h3
-rw-r--r--src/quicktemplates2/qquicktextfield.cpp97
-rw-r--r--src/quicktemplates2/qquicktextfield_p.h16
-rw-r--r--src/quicktemplates2/qquicktextfield_p_p.h1
-rw-r--r--src/quicktemplates2/qquicktoolseparator.cpp146
-rw-r--r--src/quicktemplates2/qquicktoolseparator_p.h90
-rw-r--r--src/quicktemplates2/qquicktooltip.cpp20
-rw-r--r--src/quicktemplates2/qquicktooltip_p.h2
-rw-r--r--src/quicktemplates2/qquicktumbler.cpp585
-rw-r--r--src/quicktemplates2/qquicktumbler_p.h11
-rw-r--r--src/quicktemplates2/qquicktumbler_p_p.h113
-rw-r--r--src/quicktemplates2/quicktemplates2.pri13
58 files changed, 4118 insertions, 512 deletions
diff --git a/src/quicktemplates2/qquickabstractbutton.cpp b/src/quicktemplates2/qquickabstractbutton.cpp
index c4b2b6f0..ac5fbf55 100644
--- a/src/quicktemplates2/qquickabstractbutton.cpp
+++ b/src/quicktemplates2/qquickabstractbutton.cpp
@@ -474,8 +474,8 @@ void QQuickAbstractButton::keyPressEvent(QKeyEvent *event)
Q_D(QQuickAbstractButton);
QQuickControl::keyPressEvent(event);
if (event->key() == Qt::Key_Space) {
- setPressed(true);
d->pressPoint = QPoint(qRound(width() / 2), qRound(height() / 2));
+ setPressed(true);
if (d->autoRepeat) {
d->startRepeatDelay();
@@ -506,8 +506,8 @@ void QQuickAbstractButton::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickAbstractButton);
QQuickControl::mousePressEvent(event);
- setPressed(true);
d->pressPoint = event->pos();
+ setPressed(true);
emit pressed();
diff --git a/src/quicktemplates2/qquickabstractbutton_p_p.h b/src/quicktemplates2/qquickabstractbutton_p_p.h
index e690bbd0..a7d4d6c2 100644
--- a/src/quicktemplates2/qquickabstractbutton_p_p.h
+++ b/src/quicktemplates2/qquickabstractbutton_p_p.h
@@ -55,7 +55,7 @@ QT_BEGIN_NAMESPACE
class QQuickButtonGroup;
-class QQuickAbstractButtonPrivate : public QQuickControlPrivate
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickAbstractButtonPrivate : public QQuickControlPrivate
{
Q_DECLARE_PUBLIC(QQuickAbstractButton)
diff --git a/src/quicktemplates2/qquickapplicationwindow.cpp b/src/quicktemplates2/qquickapplicationwindow.cpp
index 2706d9b6..af14ba6f 100644
--- a/src/quicktemplates2/qquickapplicationwindow.cpp
+++ b/src/quicktemplates2/qquickapplicationwindow.cpp
@@ -42,6 +42,7 @@
#include "qquicktextfield_p.h"
#include "qquicktoolbar_p.h"
#include "qquicktabbar_p.h"
+#include "qquickdialogbuttonbox_p.h"
#include <QtCore/private/qobject_p.h>
#include <QtQuick/private/qquickitem_p.h>
@@ -68,7 +69,7 @@ QT_BEGIN_NAMESPACE
\image qtquickcontrols2-applicationwindow-wireframe.png
\qml
- import QtQuick.Controls 2.0
+ import QtQuick.Controls 2.1
ApplicationWindow {
visible: true
@@ -118,7 +119,7 @@ public:
void relayout();
- void itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect) override;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
void itemVisibilityChanged(QQuickItem *item) override;
void itemImplicitWidthChanged(QQuickItem *item) override;
void itemImplicitHeightChanged(QQuickItem *item) override;
@@ -194,11 +195,11 @@ void QQuickApplicationWindowPrivate::relayout()
}
}
-void QQuickApplicationWindowPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect)
+void QQuickApplicationWindowPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
{
Q_UNUSED(item)
- Q_UNUSED(newRect)
- Q_UNUSED(oldRect)
+ Q_UNUSED(change)
+ Q_UNUSED(diff)
relayout();
}
@@ -314,8 +315,9 @@ void QQuickApplicationWindow::setBackground(QQuickItem *background)
This property holds the window header item. The header item is positioned to
the top, and resized to the width of the window. The default value is \c null.
- \note Assigning a ToolBar or TabBar as a window header sets the respective
- \l ToolBar::position or \l TabBar::position property automatically to \c Header.
+ \note Assigning a ToolBar, TabBar, or DialogButtonBox as a window header
+ automatically sets the respective \l ToolBar::position, \l TabBar::position,
+ or \l DialogButtonBox::position property to \c Header.
\sa footer, Page::header
*/
@@ -348,6 +350,8 @@ void QQuickApplicationWindow::setHeader(QQuickItem *header)
toolBar->setPosition(QQuickToolBar::Header);
else if (QQuickTabBar *tabBar = qobject_cast<QQuickTabBar *>(header))
tabBar->setPosition(QQuickTabBar::Header);
+ else if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(header))
+ buttonBox->setPosition(QQuickDialogButtonBox::Header);
}
if (isComponentComplete())
d->relayout();
@@ -360,8 +364,9 @@ void QQuickApplicationWindow::setHeader(QQuickItem *header)
This property holds the window footer item. The footer item is positioned to
the bottom, and resized to the width of the window. The default value is \c null.
- \note Assigning a ToolBar or TabBar as a window footer sets the respective
- \l ToolBar::position or \l TabBar::position property automatically to \c Footer.
+ \note Assigning a ToolBar, TabBar, or DialogButtonBox as a window footer
+ automatically sets the respective \l ToolBar::position, \l TabBar::position,
+ or \l DialogButtonBox::position property to \c Footer.
\sa header, Page::footer
*/
@@ -394,6 +399,8 @@ void QQuickApplicationWindow::setFooter(QQuickItem *footer)
toolBar->setPosition(QQuickToolBar::Footer);
else if (QQuickTabBar *tabBar = qobject_cast<QQuickTabBar *>(footer))
tabBar->setPosition(QQuickTabBar::Footer);
+ else if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(footer))
+ buttonBox->setPosition(QQuickDialogButtonBox::Footer);
}
if (isComponentComplete())
d->relayout();
diff --git a/src/quicktemplates2/qquickbuttongroup.cpp b/src/quicktemplates2/qquickbuttongroup.cpp
index 3d3e9c05..9630cbaf 100644
--- a/src/quicktemplates2/qquickbuttongroup.cpp
+++ b/src/quicktemplates2/qquickbuttongroup.cpp
@@ -123,6 +123,32 @@ QT_BEGIN_NAMESPACE
\sa RadioButton, {Button Controls}
*/
+/*!
+ \qmlsignal QtQuick.Controls::ButtonGroup::clicked(AbstractButton button)
+ \since QtQuick.Controls 2.1
+
+ This signal is emitted when a \a button in the group has been clicked.
+
+ This signal is convenient for implementing a common signal handler for
+ all buttons in the same group.
+
+ \code
+ ButtonGroup {
+ buttons: column.children
+ onClicked: console.log("clicked:", button.text)
+ }
+
+ Column {
+ id: column
+ Button { text: "First" }
+ Button { text: "Second" }
+ Button { text: "Third" }
+ }
+ \endcode
+
+ \sa AbstractButton::clicked()
+*/
+
class QQuickButtonGroupPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QQuickButtonGroup)
@@ -131,6 +157,7 @@ public:
QQuickButtonGroupPrivate() : checkedButton(nullptr) { }
void clear();
+ void buttonClicked();
void _q_updateCurrent();
static void buttons_append(QQmlListProperty<QQuickAbstractButton> *prop, QQuickAbstractButton *obj);
@@ -146,11 +173,20 @@ void QQuickButtonGroupPrivate::clear()
{
for (QQuickAbstractButton *button : qAsConst(buttons)) {
QQuickAbstractButtonPrivate::get(button)->group = nullptr;
+ QObjectPrivate::disconnect(button, &QQuickAbstractButton::clicked, this, &QQuickButtonGroupPrivate::buttonClicked);
QObjectPrivate::disconnect(button, &QQuickAbstractButton::checkedChanged, this, &QQuickButtonGroupPrivate::_q_updateCurrent);
}
buttons.clear();
}
+void QQuickButtonGroupPrivate::buttonClicked()
+{
+ Q_Q(QQuickButtonGroup);
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton*>(q->sender());
+ if (button)
+ emit q->clicked(button);
+}
+
void QQuickButtonGroupPrivate::_q_updateCurrent()
{
Q_Q(QQuickButtonGroup);
@@ -289,6 +325,7 @@ void QQuickButtonGroup::addButton(QQuickAbstractButton *button)
return;
QQuickAbstractButtonPrivate::get(button)->group = this;
+ QObjectPrivate::connect(button, &QQuickAbstractButton::clicked, d, &QQuickButtonGroupPrivate::buttonClicked);
QObjectPrivate::connect(button, &QQuickAbstractButton::checkedChanged, d, &QQuickButtonGroupPrivate::_q_updateCurrent);
if (button->isChecked())
@@ -316,6 +353,7 @@ void QQuickButtonGroup::removeButton(QQuickAbstractButton *button)
return;
QQuickAbstractButtonPrivate::get(button)->group = nullptr;
+ QObjectPrivate::disconnect(button, &QQuickAbstractButton::clicked, d, &QQuickButtonGroupPrivate::buttonClicked);
QObjectPrivate::disconnect(button, &QQuickAbstractButton::checkedChanged, d, &QQuickButtonGroupPrivate::_q_updateCurrent);
if (d->checkedButton == button)
diff --git a/src/quicktemplates2/qquickbuttongroup_p.h b/src/quicktemplates2/qquickbuttongroup_p.h
index baf4e13f..2202ae2f 100644
--- a/src/quicktemplates2/qquickbuttongroup_p.h
+++ b/src/quicktemplates2/qquickbuttongroup_p.h
@@ -83,6 +83,7 @@ public Q_SLOTS:
Q_SIGNALS:
void checkedButtonChanged();
void buttonsChanged();
+ Q_REVISION(1) void clicked(QQuickAbstractButton *button);
private:
Q_DISABLE_COPY(QQuickButtonGroup)
diff --git a/src/quicktemplates2/qquickcombobox.cpp b/src/quicktemplates2/qquickcombobox.cpp
index 00fdd421..59c108c2 100644
--- a/src/quicktemplates2/qquickcombobox.cpp
+++ b/src/quicktemplates2/qquickcombobox.cpp
@@ -154,7 +154,7 @@ class QQuickComboBoxPrivate : public QQuickControlPrivate
Q_DECLARE_PUBLIC(QQuickComboBox)
public:
- QQuickComboBoxPrivate() : pressed(false), ownModel(false), hasDisplayText(false), hasCurrentIndex(false),
+ QQuickComboBoxPrivate() : flat(false), pressed(false), ownModel(false), hasDisplayText(false), hasCurrentIndex(false),
highlightedIndex(-1), currentIndex(-1), delegateModel(nullptr),
delegate(nullptr), indicator(nullptr), popup(nullptr) { }
@@ -174,6 +174,7 @@ public:
void createDelegateModel();
+ bool flat;
bool pressed;
bool ownModel;
bool hasDisplayText;
@@ -438,6 +439,36 @@ QQmlInstanceModel *QQuickComboBox::delegateModel() const
}
/*!
+ \since QtQuick.Controls 2.1
+ \qmlproperty bool QtQuick.Controls::ComboBox::flat
+
+ This property holds whether the combo box button is flat.
+
+ A flat combo box button does not draw a background unless it is interacted
+ with. In comparison to normal combo boxes, flat combo boxes provide looks
+ that make them stand out less from the rest of the UI. For instance, when
+ placing a combo box into a tool bar, it may be desirable to make the combo
+ box flat so it matches better with the flat looks of tool buttons.
+
+ The default value is \c false.
+*/
+bool QQuickComboBox::isFlat() const
+{
+ Q_D(const QQuickComboBox);
+ return d->flat;
+}
+
+void QQuickComboBox::setFlat(bool flat)
+{
+ Q_D(QQuickComboBox);
+ if (d->flat == flat)
+ return;
+
+ d->flat = flat;
+ emit flatChanged();
+}
+
+/*!
\qmlproperty bool QtQuick.Controls::ComboBox::pressed
This property holds whether the combo box button is pressed.
@@ -657,7 +688,7 @@ void QQuickComboBox::setPopup(QQuickPopup *popup)
delete d->popup;
if (popup) {
- QQuickPopupPrivate::get(popup)->allowVerticalFlip = true;
+ popup->setAllowVerticalFlip(true);
popup->setClosePolicy(QQuickPopup::CloseOnEscape | QQuickPopup::CloseOnPressOutsideParent);
}
d->popup = popup;
diff --git a/src/quicktemplates2/qquickcombobox_p.h b/src/quicktemplates2/qquickcombobox_p.h
index 26b7688e..3788d56a 100644
--- a/src/quicktemplates2/qquickcombobox_p.h
+++ b/src/quicktemplates2/qquickcombobox_p.h
@@ -62,6 +62,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickComboBox : public QQuickControl
Q_PROPERTY(int count READ count NOTIFY countChanged FINAL)
Q_PROPERTY(QVariant model READ model WRITE setModel NOTIFY modelChanged FINAL)
Q_PROPERTY(QQmlInstanceModel *delegateModel READ delegateModel NOTIFY delegateModelChanged FINAL)
+ Q_PROPERTY(bool flat READ isFlat WRITE setFlat NOTIFY flatChanged FINAL REVISION 1)
Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL)
Q_PROPERTY(int highlightedIndex READ highlightedIndex NOTIFY highlightedIndexChanged FINAL)
Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL)
@@ -82,6 +83,9 @@ public:
void setModel(const QVariant &model);
QQmlInstanceModel *delegateModel() const;
+ bool isFlat() const;
+ void setFlat(bool flat);
+
bool isPressed() const;
void setPressed(bool pressed);
@@ -119,6 +123,7 @@ Q_SIGNALS:
void countChanged();
void modelChanged();
void delegateModelChanged();
+ Q_REVISION(1) void flatChanged();
void pressedChanged();
void highlightedIndexChanged();
void currentIndexChanged();
diff --git a/src/quicktemplates2/qquickcontainer.cpp b/src/quicktemplates2/qquickcontainer.cpp
index 43fda437..31a92b5d 100644
--- a/src/quicktemplates2/qquickcontainer.cpp
+++ b/src/quicktemplates2/qquickcontainer.cpp
@@ -545,7 +545,7 @@ QQmlListProperty<QQuickItem> QQuickContainer::contentChildren()
This property holds the index of the current item.
- \sa currentItem
+ \sa currentItem, incrementCurrentIndex(), decrementCurrentIndex()
*/
int QQuickContainer::currentIndex() const
{
@@ -565,6 +565,36 @@ void QQuickContainer::setCurrentIndex(int index)
}
/*!
+ \qmlmethod void QtQuick.Controls::Container::incrementCurrentIndex()
+ \since QtQuick.Controls 2.1
+
+ Increments the current index of the container.
+
+ \sa currentIndex
+*/
+void QQuickContainer::incrementCurrentIndex()
+{
+ Q_D(QQuickContainer);
+ if (d->currentIndex < count() - 1)
+ setCurrentIndex(d->currentIndex + 1);
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Container::decrementCurrentIndex()
+ \since QtQuick.Controls 2.1
+
+ Decrements the current index of the container.
+
+ \sa currentIndex
+*/
+void QQuickContainer::decrementCurrentIndex()
+{
+ Q_D(QQuickContainer);
+ if (d->currentIndex > 0)
+ setCurrentIndex(d->currentIndex - 1);
+}
+
+/*!
\qmlproperty Item QtQuick.Controls::Container::currentItem
\readonly
diff --git a/src/quicktemplates2/qquickcontainer_p.h b/src/quicktemplates2/qquickcontainer_p.h
index 2ed30b77..98873c09 100644
--- a/src/quicktemplates2/qquickcontainer_p.h
+++ b/src/quicktemplates2/qquickcontainer_p.h
@@ -86,6 +86,8 @@ public:
public Q_SLOTS:
void setCurrentIndex(int index);
+ Q_REVISION(1) void incrementCurrentIndex();
+ Q_REVISION(1) void decrementCurrentIndex();
Q_SIGNALS:
void countChanged();
diff --git a/src/quicktemplates2/qquickdialog.cpp b/src/quicktemplates2/qquickdialog.cpp
new file mode 100644
index 00000000..eaa7dbb2
--- /dev/null
+++ b/src/quicktemplates2/qquickdialog.cpp
@@ -0,0 +1,386 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickdialog_p.h"
+#include "qquickdialog_p_p.h"
+#include "qquickdialogbuttonbox_p.h"
+
+#include <QtQml/qqmlinfo.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlcomponent.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype Dialog
+ \inherits Popup
+ \instantiates QQuickDialog
+ \inqmlmodule QtQuick.Controls
+ \ingroup qtquickcontrols2-dialogs
+ \ingroup qtquickcontrols2-popups
+ \brief A dialog control.
+ \since 5.8
+
+ A dialog is a popup mostly used for short-term tasks and brief communications
+ with the user. Similarly to \l ApplicationWindow and \l Page, Dialog is organized
+ into three sections: \l header, \l {Popup::}{contentItem}, and \l footer.
+
+ \image qtquickcontrols2-page-wireframe.png
+
+ \section1 Dialog Buttons
+
+ Dialog's standard buttons are managed by \l DialogButtonBox. When a button box
+ is assigned as a dialog \l footer or \l header, the dialog's \l standardButtons
+ property is forwarded to the respective property of the button box. Furthermore,
+ the \l {DialogButtonBox::}{accepted()} and \l {DialogButtonBox::}{rejected()}
+ signals of the button box are connected to the respective signals in Dialog.
+
+ \snippet qtquickcontrols2-dialog.qml 1
+
+ \note If any standard buttons are specified for the dialog but no button box has
+ been assigned as a footer or header, Dialog automatically creates an instance of
+ \l buttonBox, and assigns it as a footer or header of the dialog depending on the
+ value of the \l {DialogButtonBox::}{position} property. All built-in Dialog styles
+ assign the button box as a footer.
+
+ \section1 Modal Dialogs
+
+ A \l {Popup::}{modal} dialog blocks input to other content beneath
+ the dialog. When a modal dialog is opened, the user must finish
+ interacting with the dialog and close it before they can access any
+ other content in the same window.
+
+ \snippet qtquickcontrols2-dialog-modal.qml 1
+
+ \section1 Modeless Dialogs
+
+ A modeless dialog is a dialog that operates independently of other
+ content around the dialog. When a modeless dialog is opened, the user
+ is allowed to interact with both the dialog and the other content in
+ the same window.
+
+ \snippet qtquickcontrols2-dialog-modeless.qml 1
+
+ \sa DialogButtonBox, {Popup Controls}
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::Dialog::accepted()
+
+ This signal is emitted when the dialog has been accepted either
+ interactively or by calling \l accept().
+
+ \note This signal is \e not emitted when closing the dialog with
+ \l {Popup::}{close()} or setting \l {Popup::}{visible} to \c false.
+
+ \sa rejected()
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::Dialog::rejected()
+
+ This signal is emitted when the dialog has been rejected either
+ interactively or by calling \l reject().
+
+ \note This signal is \e not emitted when closing the dialog with
+ \l {Popup::}{close()} or setting \l {Popup::}{visible} to \c false.
+
+ \sa accepted()
+*/
+
+void QQuickDialogPrivate::createButtonBox()
+{
+ Q_Q(QQuickDialog);
+ QQmlContext *context = qmlContext(q);
+ if (!context || !buttonBoxComponent)
+ return;
+
+ QObject *object = buttonBoxComponent->create(context);
+ QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(object);
+ if (!buttonBox) {
+ if (object) {
+ qmlInfo(q) << "buttonBox must be an instance of DialogButtonBox";
+ delete object;
+ }
+ return;
+ }
+
+ if (buttonBox->position() == QQuickDialogButtonBox::Header) {
+ if (layout->header()) {
+ qmlInfo(q) << "Custom header detected. Cannot assign buttonBox as a header. No standard buttons will appear in the header.";
+ delete buttonBox;
+ } else {
+ q->setHeader(buttonBox);
+ }
+ } else {
+ if (layout->footer()) {
+ qmlInfo(q) << "Custom footer detected. Cannot assign buttonBox as a footer. No standard buttons will appear in the footer.";
+ delete buttonBox;
+ } else {
+ q->setFooter(buttonBox);
+ }
+ }
+}
+
+QQuickDialog::QQuickDialog(QObject *parent) :
+ QQuickPopup(*(new QQuickDialogPrivate), parent)
+{
+ Q_D(QQuickDialog);
+ d->layout.reset(new QQuickPageLayout(d->popupItem));
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Dialog::header
+
+ This property holds the dialog header item. The header item is positioned to
+ the top, and resized to the width of the dialog. The default value is \c null.
+
+ \note Assigning a \l DialogButtonBox as a dialog header automatically connects
+ its \l {DialogButtonBox::}{accepted()} and \l {DialogButtonBox::}{rejected()}
+ signals to the respective signals in Dialog.
+
+ \note Assigning a \l DialogButtonBox, \l ToolBar, or \l TabBar as a dialog
+ header automatically sets the respective \l DialogButtonBox::position,
+ \l ToolBar::position, or \l TabBar::position property to \c Header.
+
+ \sa footer, buttonBox
+*/
+QQuickItem *QQuickDialog::header() const
+{
+ Q_D(const QQuickDialog);
+ return d->layout->header();
+}
+
+void QQuickDialog::setHeader(QQuickItem *header)
+{
+ Q_D(QQuickDialog);
+ QQuickItem *oldHeader = d->layout->header();
+ if (!d->layout->setHeader(header))
+ return;
+
+ if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(oldHeader)) {
+ disconnect(buttonBox, &QQuickDialogButtonBox::accepted, this, &QQuickDialog::accept);
+ disconnect(buttonBox, &QQuickDialogButtonBox::rejected, this, &QQuickDialog::reject);
+ if (d->buttonBox == buttonBox)
+ d->buttonBox = nullptr;
+ }
+ if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(header)) {
+ connect(buttonBox, &QQuickDialogButtonBox::accepted, this, &QQuickDialog::accept);
+ connect(buttonBox, &QQuickDialogButtonBox::rejected, this, &QQuickDialog::reject);
+ d->buttonBox = buttonBox;
+ buttonBox->setStandardButtons(d->standardButtons);
+ }
+
+ if (isComponentComplete())
+ d->layout->update();
+ emit headerChanged();
+}
+
+/*!
+ \qmlproperty Item QtQuick.Controls::Dialog::footer
+
+ This property holds the dialog footer item. The footer item is positioned to
+ the bottom, and resized to the width of the dialog. The default value is \c null.
+
+ \note Assigning a \l DialogButtonBox as a dialog footer automatically connects
+ its \l {DialogButtonBox::}{accepted()} and \l {DialogButtonBox::}{rejected()}
+ signals to the respective signals in Dialog.
+
+ \note Assigning a \l DialogButtonBox, \l ToolBar, or \l TabBar as a dialog
+ footer automatically sets the respective \l DialogButtonBox::position,
+ \l ToolBar::position, or \l TabBar::position property to \c Footer.
+
+ \sa header, buttonBox
+*/
+QQuickItem *QQuickDialog::footer() const
+{
+ Q_D(const QQuickDialog);
+ return d->layout->footer();
+}
+
+void QQuickDialog::setFooter(QQuickItem *footer)
+{
+ Q_D(QQuickDialog);
+ QQuickItem *oldFooter = d->layout->footer();
+ if (!d->layout->setFooter(footer))
+ return;
+
+ if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(oldFooter)) {
+ disconnect(buttonBox, &QQuickDialogButtonBox::accepted, this, &QQuickDialog::accept);
+ disconnect(buttonBox, &QQuickDialogButtonBox::rejected, this, &QQuickDialog::reject);
+ if (d->buttonBox == buttonBox)
+ d->buttonBox = nullptr;
+ }
+ if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(footer)) {
+ connect(buttonBox, &QQuickDialogButtonBox::accepted, this, &QQuickDialog::accept);
+ connect(buttonBox, &QQuickDialogButtonBox::rejected, this, &QQuickDialog::reject);
+ d->buttonBox = buttonBox;
+ buttonBox->setStandardButtons(d->standardButtons);
+ }
+
+ if (isComponentComplete())
+ d->layout->update();
+ emit footerChanged();
+}
+
+/*!
+ \qmlproperty Component QtQuick.Controls::Dialog::buttonBox
+
+ This property holds a delegate for creating a button box.
+
+ A button box is only created if any standard buttons are set.
+ The \l {DialogButtonBox::}{position} property determines whether
+ the button box is assigned as a \l header or \l footer.
+
+ \sa standardButtons, header, footer, DialogButtonBox
+*/
+QQmlComponent *QQuickDialog::buttonBox() const
+{
+ Q_D(const QQuickDialog);
+ return d->buttonBoxComponent;
+}
+
+void QQuickDialog::setButtonBox(QQmlComponent *box)
+{
+ Q_D(QQuickDialog);
+ if (d->buttonBoxComponent == box)
+ return;
+
+ d->buttonBoxComponent = box;
+ emit buttonBoxChanged();
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::Dialog::standardButtons
+
+ This property holds a combination of standard buttons that are used by the dialog.
+
+ \snippet qtquickcontrols2-dialog.qml 1
+
+ Possible flags:
+ \value Dialog.Ok An "OK" button defined with the \c AcceptRole.
+ \value Dialog.Open An "Open" button defined with the \c AcceptRole.
+ \value Dialog.Save A "Save" button defined with the \c AcceptRole.
+ \value Dialog.Cancel A "Cancel" button defined with the \c RejectRole.
+ \value Dialog.Close A "Close" button defined with the \c RejectRole.
+ \value Dialog.Discard A "Discard" or "Don't Save" button, depending on the platform, defined with the \c DestructiveRole.
+ \value Dialog.Apply An "Apply" button defined with the \c ApplyRole.
+ \value Dialog.Reset A "Reset" button defined with the \c ResetRole.
+ \value Dialog.RestoreDefaults A "Restore Defaults" button defined with the \c ResetRole.
+ \value Dialog.Help A "Help" button defined with the \c HelpRole.
+ \value Dialog.SaveAll A "Save All" button defined with the \c AcceptRole.
+ \value Dialog.Yes A "Yes" button defined with the \c YesRole.
+ \value Dialog.YesToAll A "Yes to All" button defined with the \c YesRole.
+ \value Dialog.No A "No" button defined with the \c NoRole.
+ \value Dialog.NoToAll A "No to All" button defined with the \c NoRole.
+ \value Dialog.Abort An "Abort" button defined with the \c RejectRole.
+ \value Dialog.Retry A "Retry" button defined with the \c AcceptRole.
+ \value Dialog.Ignore An "Ignore" button defined with the \c AcceptRole.
+ \value Dialog.NoButton An invalid button.
+
+ \sa buttonBox, DialogButtonBox
+*/
+QPlatformDialogHelper::StandardButtons QQuickDialog::standardButtons() const
+{
+ Q_D(const QQuickDialog);
+ return d->standardButtons;
+}
+
+void QQuickDialog::setStandardButtons(QPlatformDialogHelper::StandardButtons buttons)
+{
+ Q_D(QQuickDialog);
+ if (d->standardButtons == buttons)
+ return;
+
+ d->standardButtons = buttons;
+ if (isComponentComplete()) {
+ if (d->buttonBox)
+ d->buttonBox->setStandardButtons(buttons);
+ else if (buttons)
+ d->createButtonBox();
+ }
+ emit standardButtonsChanged();
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Dialog::accept()
+
+ Closes the dialog and emits the \l accepted() signal.
+
+ \sa reject()
+*/
+void QQuickDialog::accept()
+{
+ close();
+ emit accepted();
+}
+
+/*!
+ \qmlmethod void QtQuick.Controls::Dialog::reject()
+
+ Closes the dialog and emits the \l rejected() signal.
+
+ \sa accept()
+*/
+void QQuickDialog::reject()
+{
+ close();
+ emit rejected();
+}
+
+void QQuickDialog::componentComplete()
+{
+ Q_D(QQuickDialog);
+ QQuickPopup::componentComplete();
+ if (!d->buttonBox && d->standardButtons)
+ d->createButtonBox();
+}
+
+void QQuickDialog::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickDialog);
+ QQuickPopup::geometryChanged(newGeometry, oldGeometry);
+ d->layout->update();
+}
+
+void QQuickDialog::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding)
+{
+ Q_D(QQuickDialog);
+ QQuickPopup::paddingChange(newPadding, oldPadding);
+ d->layout->update();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickdialog_p.h b/src/quicktemplates2/qquickdialog_p.h
new file mode 100644
index 00000000..2c7eee95
--- /dev/null
+++ b/src/quicktemplates2/qquickdialog_p.h
@@ -0,0 +1,110 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDIALOG_P_H
+#define QQUICKDIALOG_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuickTemplates2/private/qquickpopup_p.h>
+#include <QtGui/qpa/qplatformdialoghelper.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlComponent;
+class QQuickDialogPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickDialog : public QQuickPopup
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickItem *header READ header WRITE setHeader NOTIFY headerChanged FINAL)
+ Q_PROPERTY(QQuickItem *footer READ footer WRITE setFooter NOTIFY footerChanged FINAL)
+ Q_PROPERTY(QQmlComponent *buttonBox READ buttonBox WRITE setButtonBox NOTIFY buttonBoxChanged FINAL)
+ Q_PROPERTY(QPlatformDialogHelper::StandardButtons standardButtons READ standardButtons WRITE setStandardButtons NOTIFY standardButtonsChanged FINAL)
+ Q_FLAGS(QPlatformDialogHelper::StandardButtons)
+
+public:
+ explicit QQuickDialog(QObject *parent = nullptr);
+
+ QQuickItem *header() const;
+ void setHeader(QQuickItem *header);
+
+ QQuickItem *footer() const;
+ void setFooter(QQuickItem *footer);
+
+ QQmlComponent *buttonBox() const;
+ void setButtonBox(QQmlComponent *box);
+
+ QPlatformDialogHelper::StandardButtons standardButtons() const;
+ void setStandardButtons(QPlatformDialogHelper::StandardButtons buttons);
+
+public Q_SLOTS:
+ void accept();
+ void reject();
+
+Q_SIGNALS:
+ void accepted();
+ void rejected();
+
+ void headerChanged();
+ void footerChanged();
+ void buttonBoxChanged();
+ void standardButtonsChanged();
+
+protected:
+ void componentComplete() override;
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding) override;
+
+private:
+ Q_DISABLE_COPY(QQuickDialog)
+ Q_DECLARE_PRIVATE(QQuickDialog)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickDialog)
+
+#endif // QQUICKDIALOG_P_H
diff --git a/src/quicktemplates2/qquickdialog_p_p.h b/src/quicktemplates2/qquickdialog_p_p.h
new file mode 100644
index 00000000..a893690d
--- /dev/null
+++ b/src/quicktemplates2/qquickdialog_p_p.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDIALOG_P_P_H
+#define QQUICKDIALOG_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuickTemplates2/private/qquickpopup_p_p.h>
+#include <QtQuickTemplates2/private/qquickpagelayout_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlComponent;
+class QQuickDialogButtonBox;
+
+class QQuickDialogPrivate : public QQuickPopupPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickDialog)
+
+public:
+ QQuickDialogPrivate() : buttonBox(nullptr), buttonBoxComponent(nullptr) { }
+
+ static QQuickDialogPrivate *get(QQuickDialog *dialog)
+ {
+ return dialog->d_func();
+ }
+
+ void createButtonBox();
+
+ QQuickDialogButtonBox *buttonBox;
+ QQmlComponent *buttonBoxComponent;
+ QScopedPointer<QQuickPageLayout> layout;
+ QPlatformDialogHelper::StandardButtons standardButtons;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKDIALOG_P_P_H
diff --git a/src/quicktemplates2/qquickdialogbuttonbox.cpp b/src/quicktemplates2/qquickdialogbuttonbox.cpp
new file mode 100644
index 00000000..10603d58
--- /dev/null
+++ b/src/quicktemplates2/qquickdialogbuttonbox.cpp
@@ -0,0 +1,672 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickdialogbuttonbox_p.h"
+#include "qquickdialogbuttonbox_p_p.h"
+#include "qquickabstractbutton_p.h"
+#include "qquickbutton_p.h"
+
+#include <QtCore/qpointer.h>
+#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/qpa/qplatformtheme.h>
+#include <QtQml/qqmlengine.h>
+#include <QtQml/qqmlcontext.h>
+#include <QtQml/qqmlcomponent.h>
+
+#include <algorithm>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype DialogButtonBox
+ \inherits Container
+ \instantiates QQuickDialogButtonBox
+ \inqmlmodule QtQuick.Controls
+ \ingroup qtquickcontrols2-dialogs
+ \brief A button box used in dialogs.
+ \since 5.8
+
+ Dialogs and message boxes typically present buttons in an order that
+ conforms to the interface guidelines for that platform. Invariably,
+ different platforms have their dialog buttons in different orders.
+ DialogButtonBox allows a developer to add buttons to it and will
+ automatically use the appropriate order for the user's platform.
+
+ Most buttons for a dialog follow certain roles. Such roles include:
+
+ \list
+ \li Accepting or rejecting the dialog.
+ \li Asking for help.
+ \li Performing actions on the dialog itself (such as resetting fields or
+ applying changes).
+ \endlist
+
+ There can also be alternate ways of dismissing the dialog which may cause
+ destructive results.
+
+ Most dialogs have buttons that can almost be considered standard (e.g.
+ \uicontrol OK and \uicontrol Cancel buttons). It is sometimes convenient
+ to create these buttons in a standard way.
+
+ There are a couple ways of using DialogButtonBox. One way is to specify
+ the standard buttons (e.g. \uicontrol OK, \uicontrol Cancel, \uicontrol Save)
+ and let the button box setup the buttons.
+
+ \image qtquickcontrols2-dialogbuttonbox.png
+
+ \snippet qtquickcontrols2-dialogbuttonbox.qml 1
+
+ Alternatively, buttons and their roles can be specified by hand:
+
+ \snippet qtquickcontrols2-dialogbuttonbox-attached.qml 1
+
+ You can also mix and match normal buttons and standard buttons.
+
+ When a button is clicked in the button box, the \l clicked() signal is
+ emitted for the actual button that is pressed. For convenience, if the
+ button has an \c AcceptRole, \c RejectRole, or \c HelpRole, the \l accepted(),
+ \l rejected(), or \l helpRequested() signals are emitted respectively.
+
+ \sa Dialog
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::DialogButtonBox::accepted()
+
+ This signal is emitted when a button defined with the \c AcceptRole or
+ \c YesRole is clicked.
+
+ \sa rejected(), clicked(), helpRequested()
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::DialogButtonBox::rejected()
+
+ This signal is emitted when a button defined with the \c RejectRole or
+ \c NoRole is clicked.
+
+ \sa accepted(), helpRequested(), clicked()
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::DialogButtonBox::helpRequested()
+
+ This signal is emitted when a button defined with the \c HelpRole is clicked.
+
+ \sa accepted(), rejected(), clicked()
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::DialogButtonBox::clicked(AbstractButton button)
+
+ This signal is emitted when a \a button inside the button box is clicked.
+
+ \sa accepted(), rejected(), helpRequested()
+*/
+
+static QPlatformDialogHelper::ButtonRole buttonRole(QQuickAbstractButton *button)
+{
+ const QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(qmlAttachedPropertiesObject<QQuickDialogButtonBox>(button, false));
+ return attached ? attached->buttonRole() : QPlatformDialogHelper::InvalidRole;
+}
+
+QQuickDialogButtonBoxPrivate::QQuickDialogButtonBoxPrivate() :
+ alignment(0),
+ position(QQuickDialogButtonBox::Footer),
+ standardButtons(QPlatformDialogHelper::NoButton),
+ delegate(nullptr)
+{
+}
+
+void QQuickDialogButtonBoxPrivate::itemImplicitWidthChanged(QQuickItem *item)
+{
+ Q_UNUSED(item);
+ resizeContent();
+}
+
+void QQuickDialogButtonBoxPrivate::itemImplicitHeightChanged(QQuickItem *item)
+{
+ Q_UNUSED(item);
+ resizeContent();
+}
+
+// adapted from QStyle::alignedRect()
+static QRectF alignedRect(Qt::LayoutDirection direction, Qt::Alignment alignment, const QSizeF &size, const QRectF &rectangle)
+{
+ alignment = QGuiApplicationPrivate::visualAlignment(direction, alignment);
+ qreal x = rectangle.x();
+ qreal y = rectangle.y();
+ qreal w = size.width();
+ qreal h = size.height();
+ if ((alignment & Qt::AlignVCenter) == Qt::AlignVCenter)
+ y += rectangle.size().height() / 2 - h / 2;
+ else if ((alignment & Qt::AlignBottom) == Qt::AlignBottom)
+ y += rectangle.size().height() - h;
+ if ((alignment & Qt::AlignRight) == Qt::AlignRight)
+ x += rectangle.size().width() - w;
+ else if ((alignment & Qt::AlignHCenter) == Qt::AlignHCenter)
+ x += rectangle.size().width() / 2 - w / 2;
+ return QRectF(x, y, w, h);
+}
+
+void QQuickDialogButtonBoxPrivate::resizeContent()
+{
+ Q_Q(QQuickDialogButtonBox);
+ if (!contentItem)
+ return;
+
+ const int halign = alignment & Qt::AlignHorizontal_Mask;
+ const int valign = alignment & Qt::AlignVertical_Mask;
+
+ const qreal cw = !halign ? q->availableWidth() : contentItem->implicitWidth();
+ const qreal ch = !valign ? q->availableHeight() : contentItem->implicitWidth();
+
+ QRectF geometry = q->boundingRect().adjusted(q->leftPadding(), q->topPadding(), -q->rightPadding(), -q->bottomPadding());
+ if (halign || valign)
+ geometry = alignedRect(q->isMirrored() ? Qt::RightToLeft : Qt::LeftToRight, alignment, QSizeF(cw, ch), geometry);
+
+ contentItem->setPosition(geometry.topLeft());
+ contentItem->setSize(geometry.size());
+}
+
+void QQuickDialogButtonBoxPrivate::updateLayout()
+{
+ Q_Q(QQuickDialogButtonBox);
+ const int count = contentModel->count();
+ if (count <= 0)
+ return;
+
+ const int halign = alignment & Qt::AlignHorizontal_Mask;
+ const int valign = alignment & Qt::AlignVertical_Mask;
+
+ QVector<QQuickAbstractButton *> buttons;
+ const qreal maxItemWidth = (contentItem->width() - qMax(0, count - 1) * spacing) / count;
+ const qreal maxItemHeight = contentItem->height();
+
+ for (int i = 0; i < count; ++i) {
+ QQuickItem *item = q->itemAt(i);
+ if (item) {
+ QQuickItemPrivate *p = QQuickItemPrivate::get(item);
+ if (!p->widthValid) {
+ if (!halign)
+ item->setWidth(maxItemWidth);
+ else
+ item->resetWidth();
+ if (!valign)
+ item->setHeight(maxItemHeight);
+ else
+ item->resetHeight();
+ p->widthValid = false;
+ }
+ }
+ buttons += static_cast<QQuickAbstractButton *>(item);
+ }
+
+ struct ButtonLayout {
+ bool operator()(QQuickAbstractButton *first, QQuickAbstractButton *second)
+ {
+ const QPlatformDialogHelper::ButtonRole firstRole = buttonRole(first);
+ const QPlatformDialogHelper::ButtonRole secondRole = buttonRole(second);
+
+ if (firstRole != secondRole && firstRole != QPlatformDialogHelper::InvalidRole && secondRole != QPlatformDialogHelper::InvalidRole) {
+ const int *l = m_layout;
+ while (*l != QPlatformDialogHelper::EOL) {
+ const int role = (*l & ~QPlatformDialogHelper::Reverse);
+ if (role == firstRole)
+ return true;
+ if (role == secondRole)
+ return false;
+ ++l;
+ }
+ }
+
+ if (firstRole == secondRole)
+ return first < second;
+
+ return firstRole != QPlatformDialogHelper::InvalidRole;
+ }
+ const int *m_layout = QPlatformDialogHelper::buttonLayout();
+ };
+
+ std::sort(buttons.begin(), buttons.end(), ButtonLayout());
+
+ for (int i = 0; i < buttons.count() - 1; ++i)
+ q->insertItem(i, buttons.at(i));
+}
+
+void QQuickDialogButtonBoxPrivate::handleClick()
+{
+ Q_Q(QQuickDialogButtonBox);
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(q->sender());
+ if (!button)
+ return;
+
+ // Can't fetch this *after* emitting clicked, as clicked may destroy the button
+ // or change its role. Now changing the role is not possible yet, but arguably
+ // both clicked and accepted/rejected/etc. should be emitted "atomically"
+ // depending on whatever role the button had at the time of the click.
+ const QPlatformDialogHelper::ButtonRole role = buttonRole(button);
+ QPointer<QQuickDialogButtonBox> guard(q);
+
+ emit q->clicked(button);
+
+ if (!guard)
+ return;
+
+ switch (role) {
+ case QPlatformDialogHelper::AcceptRole:
+ case QPlatformDialogHelper::YesRole:
+ emit q->accepted();
+ break;
+ case QPlatformDialogHelper::RejectRole:
+ case QPlatformDialogHelper::NoRole:
+ emit q->rejected();
+ break;
+ case QPlatformDialogHelper::HelpRole:
+ emit q->helpRequested();
+ break;
+ default:
+ break;
+ }
+}
+
+QQuickAbstractButton *QQuickDialogButtonBoxPrivate::createStandardButton(QPlatformDialogHelper::StandardButton standardButton)
+{
+ Q_Q(QQuickDialogButtonBox);
+ if (!delegate)
+ return nullptr;
+
+ QQmlContext *creationContext = delegate->creationContext();
+ if (!creationContext)
+ creationContext = qmlContext(q);
+ QQmlContext *context = new QQmlContext(creationContext);
+ context->setContextObject(q);
+
+ QObject *object = delegate->beginCreate(context);
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton*>(object);
+ if (button) {
+ QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(qmlAttachedPropertiesObject<QQuickDialogButtonBox>(button, true));
+ QQuickDialogButtonBoxAttachedPrivate::get(attached)->standardButton = standardButton;
+ attached->setButtonRole(QPlatformDialogHelper::buttonRole(standardButton));
+ button->setText(QPlatformTheme::removeMnemonics(QGuiApplicationPrivate::platformTheme()->standardButtonText(standardButton)));
+ delegate->completeCreate();
+ return button;
+ }
+
+ delete object;
+ return nullptr;
+}
+
+void QQuickDialogButtonBoxPrivate::removeStandardButtons()
+{
+ Q_Q(QQuickDialogButtonBox);
+ int i = q->count() - 1;
+ while (i >= 0) {
+ QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(q->itemAt(i));
+ if (button) {
+ QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(qmlAttachedPropertiesObject<QQuickDialogButtonBox>(button, false));
+ if (attached) {
+ QQuickDialogButtonBoxAttachedPrivate *p = QQuickDialogButtonBoxAttachedPrivate::get(attached);
+ if (p->standardButton != QPlatformDialogHelper::NoButton) {
+ q->removeItem(i);
+ button->deleteLater();
+ }
+ }
+ }
+ --i;
+ }
+}
+
+QQuickDialogButtonBox::QQuickDialogButtonBox(QQuickItem *parent) :
+ QQuickContainer(*(new QQuickDialogButtonBoxPrivate), parent)
+{
+}
+
+QQuickDialogButtonBox::~QQuickDialogButtonBox()
+{
+}
+
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::DialogButtonBox::position
+
+ This property holds the position of the button box.
+
+ \note If the button box is assigned as a header or footer of ApplicationWindow
+ or Page, the appropriate position is set automatically.
+
+ Possible values:
+ \value DialogButtonBox.Header The button box is at the top, as a window or page header.
+ \value DialogButtonBox.Footer The button box is at the bottom, as a window or page header.
+
+ The default value is \c Footer.
+
+ \sa Dialog::header, Dialog::footer
+*/
+QQuickDialogButtonBox::Position QQuickDialogButtonBox::position() const
+{
+ Q_D(const QQuickDialogButtonBox);
+ return d->position;
+}
+
+void QQuickDialogButtonBox::setPosition(Position position)
+{
+ Q_D(QQuickDialogButtonBox);
+ if (d->position == position)
+ return;
+
+ d->position = position;
+ emit positionChanged();
+}
+
+/*!
+ \qmlproperty flags QtQuick.Controls::DialogButtonBox::alignment
+
+ This property holds the alignment of the buttons.
+
+ Possible values:
+ \value undefined The buttons are resized to fill the available space.
+ \value Qt.AlignLeft The buttons are aligned to the left.
+ \value Qt.AlignHCenter The buttons are horizontally centered.
+ \value Qt.AlignRight The buttons are aligned to the right.
+ \value Qt.AlignTop The buttons are aligned to the top.
+ \value Qt.AlignVCenter The buttons are vertically centered.
+ \value Qt.AlignBottom The buttons are aligned to the bottom.
+*/
+Qt::Alignment QQuickDialogButtonBox::alignment() const
+{
+ Q_D(const QQuickDialogButtonBox);
+ return d->alignment;
+}
+
+void QQuickDialogButtonBox::setAlignment(Qt::Alignment alignment)
+{
+ Q_D(QQuickDialogButtonBox);
+ if (d->alignment == alignment)
+ return;
+
+ d->alignment = alignment;
+ if (isComponentComplete()) {
+ d->resizeContent();
+ polish();
+ }
+ emit alignmentChanged();
+}
+
+void QQuickDialogButtonBox::resetAlignment()
+{
+ setAlignment(0);
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::DialogButtonBox::standardButtons
+
+ This property holds a combination of standard buttons that are used by the button box.
+
+ \snippet qtquickcontrols2-dialogbuttonbox.qml 1
+
+ Possible flags:
+ \value DialogButtonBox.Ok An "OK" button defined with the \c AcceptRole.
+ \value DialogButtonBox.Open An "Open" button defined with the \c AcceptRole.
+ \value DialogButtonBox.Save A "Save" button defined with the \c AcceptRole.
+ \value DialogButtonBox.Cancel A "Cancel" button defined with the \c RejectRole.
+ \value DialogButtonBox.Close A "Close" button defined with the \c RejectRole.
+ \value DialogButtonBox.Discard A "Discard" or "Don't Save" button, depending on the platform, defined with the \c DestructiveRole.
+ \value DialogButtonBox.Apply An "Apply" button defined with the \c ApplyRole.
+ \value DialogButtonBox.Reset A "Reset" button defined with the \c ResetRole.
+ \value DialogButtonBox.RestoreDefaults A "Restore Defaults" button defined with the \c ResetRole.
+ \value DialogButtonBox.Help A "Help" button defined with the \c HelpRole.
+ \value DialogButtonBox.SaveAll A "Save All" button defined with the \c AcceptRole.
+ \value DialogButtonBox.Yes A "Yes" button defined with the \c YesRole.
+ \value DialogButtonBox.YesToAll A "Yes to All" button defined with the \c YesRole.
+ \value DialogButtonBox.No A "No" button defined with the \c NoRole.
+ \value DialogButtonBox.NoToAll A "No to All" button defined with the \c NoRole.
+ \value DialogButtonBox.Abort An "Abort" button defined with the \c RejectRole.
+ \value DialogButtonBox.Retry A "Retry" button defined with the \c AcceptRole.
+ \value DialogButtonBox.Ignore An "Ignore" button defined with the \c AcceptRole.
+ \value DialogButtonBox.NoButton An invalid button.
+
+ \sa standardButton()
+*/
+QPlatformDialogHelper::StandardButtons QQuickDialogButtonBox::standardButtons() const
+{
+ Q_D(const QQuickDialogButtonBox);
+ return d->standardButtons;
+}
+
+void QQuickDialogButtonBox::setStandardButtons(QPlatformDialogHelper::StandardButtons buttons)
+{
+ Q_D(QQuickDialogButtonBox);
+ if (d->standardButtons == buttons)
+ return;
+
+ d->removeStandardButtons();
+
+ for (int i = QPlatformDialogHelper::FirstButton; i <= QPlatformDialogHelper::LastButton; i<<=1) {
+ QPlatformDialogHelper::StandardButton standardButton = static_cast<QPlatformDialogHelper::StandardButton>(i);
+ if (standardButton & buttons) {
+ QQuickAbstractButton *button = d->createStandardButton(standardButton);
+ if (button)
+ addItem(button);
+ }
+ }
+
+ if (isComponentComplete())
+ polish();
+
+ d->standardButtons = buttons;
+ emit standardButtonsChanged();
+}
+
+/*!
+ \qmlmethod AbstractButton QtQuick.Controls::DialogButtonBox::standardButton(StandardButton button)
+
+ Returns the specified standard \a button, or \c null if it does not exist.
+
+ \sa standardButtons
+*/
+QQuickAbstractButton *QQuickDialogButtonBox::standardButton(QPlatformDialogHelper::StandardButton button) const
+{
+ Q_UNUSED(button);
+ return nullptr;
+}
+
+/*!
+ \qmlproperty Component QtQuick.Controls::DialogButtonBox::delegate
+
+ This property holds a delegate for creating standard buttons.
+
+ \sa standardButtons
+*/
+QQmlComponent *QQuickDialogButtonBox::delegate() const
+{
+ Q_D(const QQuickDialogButtonBox);
+ return d->delegate;
+}
+
+void QQuickDialogButtonBox::setDelegate(QQmlComponent* delegate)
+{
+ Q_D(QQuickDialogButtonBox);
+ if (d->delegate == delegate)
+ return;
+
+ delete d->delegate;
+ d->delegate = delegate;
+ emit delegateChanged();
+}
+
+QQuickDialogButtonBoxAttached *QQuickDialogButtonBox::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickDialogButtonBoxAttached(object);
+}
+
+void QQuickDialogButtonBox::updatePolish()
+{
+ Q_D(QQuickDialogButtonBox);
+ QQuickContainer::updatePolish();
+ d->updateLayout();
+}
+
+void QQuickDialogButtonBox::componentComplete()
+{
+ Q_D(QQuickDialogButtonBox);
+ QQuickContainer::componentComplete();
+ d->updateLayout();
+}
+
+void QQuickDialogButtonBox::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickDialogButtonBox);
+ QQuickContainer::geometryChanged(newGeometry, oldGeometry);
+ d->updateLayout();
+}
+
+void QQuickDialogButtonBox::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
+{
+ Q_D(QQuickDialogButtonBox);
+ QQuickContainer::contentItemChange(newItem, oldItem);
+ if (oldItem)
+ QQuickItemPrivate::get(oldItem)->removeItemChangeListener(d, QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
+ if (newItem)
+ QQuickItemPrivate::get(newItem)->addItemChangeListener(d, QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
+}
+
+bool QQuickDialogButtonBox::isContent(QQuickItem *item) const
+{
+ return qobject_cast<QQuickAbstractButton *>(item);
+}
+
+void QQuickDialogButtonBox::itemAdded(int index, QQuickItem *item)
+{
+ Q_D(QQuickDialogButtonBox);
+ Q_UNUSED(index);
+ if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(item))
+ QObjectPrivate::connect(button, &QQuickAbstractButton::clicked, d, &QQuickDialogButtonBoxPrivate::handleClick);
+ if (QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(qmlAttachedPropertiesObject<QQuickDialogButtonBox>(item, false)))
+ QQuickDialogButtonBoxAttachedPrivate::get(attached)->setButtonBox(this);
+ if (isComponentComplete())
+ polish();
+}
+
+void QQuickDialogButtonBox::itemRemoved(int index, QQuickItem *item)
+{
+ Q_D(QQuickDialogButtonBox);
+ Q_UNUSED(index);
+ if (QQuickAbstractButton *button = qobject_cast<QQuickAbstractButton *>(item))
+ QObjectPrivate::disconnect(button, &QQuickAbstractButton::clicked, d, &QQuickDialogButtonBoxPrivate::handleClick);
+ if (QQuickDialogButtonBoxAttached *attached = qobject_cast<QQuickDialogButtonBoxAttached *>(qmlAttachedPropertiesObject<QQuickDialogButtonBox>(item, false)))
+ QQuickDialogButtonBoxAttachedPrivate::get(attached)->setButtonBox(nullptr);
+ if (isComponentComplete())
+ polish();
+}
+
+#ifndef QT_NO_ACCESSIBILITY
+QAccessible::Role QQuickDialogButtonBox::accessibleRole() const
+{
+ return QAccessible::PageTabList;
+}
+#endif
+
+void QQuickDialogButtonBoxAttachedPrivate::setButtonBox(QQuickDialogButtonBox *box)
+{
+ Q_Q(QQuickDialogButtonBoxAttached);
+ if (buttonBox == box)
+ return;
+
+ buttonBox = box;
+ emit q->buttonBoxChanged();
+}
+
+QQuickDialogButtonBoxAttached::QQuickDialogButtonBoxAttached(QObject *parent) :
+ QObject(*(new QQuickDialogButtonBoxAttachedPrivate), parent)
+{
+ Q_D(QQuickDialogButtonBoxAttached);
+ QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent);
+ while (parentItem && !d->buttonBox) {
+ d->buttonBox = qobject_cast<QQuickDialogButtonBox *>(parentItem);
+ parentItem = parentItem->parentItem();
+ }
+}
+
+/*!
+ \qmlattachedproperty DialogButtonBox QtQuick.Controls::DialogButtonBox::buttonBox
+ \readonly
+
+ This attached property holds the button box that manages this button, or
+ \c null if the button is not in a button box.
+*/
+QQuickDialogButtonBox *QQuickDialogButtonBoxAttached::buttonBox() const
+{
+ Q_D(const QQuickDialogButtonBoxAttached);
+ return d->buttonBox;
+}
+
+/*!
+ \qmlattachedproperty enumeration QtQuick.Controls::DialogButtonBox::buttonRole
+
+ This attached property holds the role of each button in a button box.
+
+ \snippet qtquickcontrols2-dialogbuttonbox-attached.qml 1
+
+ Available values:
+ \value DialogButtonBox.InvalidRole The button is invalid.
+ \value DialogButtonBox.AcceptRole Clicking the button causes the dialog to be accepted (e.g. \uicontrol OK).
+ \value DialogButtonBox.RejectRole Clicking the button causes the dialog to be rejected (e.g. \uicontrol Cancel).
+ \value DialogButtonBox.DestructiveRole Clicking the button causes a destructive change (e.g. for discarding changes) and closes the dialog.
+ \value DialogButtonBox.ActionRole Clicking the button causes changes to the elements within the dialog.
+ \value DialogButtonBox.HelpRole The button can be clicked to request help.
+ \value DialogButtonBox.YesRole The button is a "Yes"-like button.
+ \value DialogButtonBox.NoRole The button is a "No"-like button.
+ \value DialogButtonBox.ResetRole The button resets the dialog's fields to default values.
+ \value DialogButtonBox.ApplyRole The button applies current changes.
+*/
+QPlatformDialogHelper::ButtonRole QQuickDialogButtonBoxAttached::buttonRole() const
+{
+ Q_D(const QQuickDialogButtonBoxAttached);
+ return d->buttonRole;
+}
+
+void QQuickDialogButtonBoxAttached::setButtonRole(QPlatformDialogHelper::ButtonRole role)
+{
+ Q_D(QQuickDialogButtonBoxAttached);
+ if (d->buttonRole == role)
+ return;
+
+ d->buttonRole = role;
+ emit buttonRoleChanged();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickdialogbuttonbox_p.h b/src/quicktemplates2/qquickdialogbuttonbox_p.h
new file mode 100644
index 00000000..445b645b
--- /dev/null
+++ b/src/quicktemplates2/qquickdialogbuttonbox_p.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDIALOGBUTTONBOX_P_H
+#define QQUICKDIALOGBUTTONBOX_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuickTemplates2/private/qquickcontainer_p.h>
+#include <QtGui/qpa/qplatformdialoghelper.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQmlComponent;
+class QQuickAbstractButton;
+class QQuickDialogButtonBoxPrivate;
+class QQuickDialogButtonBoxAttached;
+class QQuickDialogButtonBoxAttachedPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickDialogButtonBox : public QQuickContainer
+{
+ Q_OBJECT
+ Q_PROPERTY(Position position READ position WRITE setPosition NOTIFY positionChanged FINAL)
+ Q_PROPERTY(Qt::Alignment alignment READ alignment WRITE setAlignment RESET resetAlignment NOTIFY alignmentChanged FINAL)
+ Q_PROPERTY(QPlatformDialogHelper::StandardButtons standardButtons READ standardButtons WRITE setStandardButtons NOTIFY standardButtonsChanged FINAL)
+ Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL)
+ Q_FLAGS(QPlatformDialogHelper::StandardButtons)
+
+public:
+ explicit QQuickDialogButtonBox(QQuickItem *parent = nullptr);
+ ~QQuickDialogButtonBox();
+
+ enum Position {
+ Header,
+ Footer
+ };
+ Q_ENUM(Position)
+
+ Position position() const;
+ void setPosition(Position position);
+
+ Qt::Alignment alignment() const;
+ void setAlignment(Qt::Alignment alignment);
+ void resetAlignment();
+
+ QPlatformDialogHelper::StandardButtons standardButtons() const;
+ void setStandardButtons(QPlatformDialogHelper::StandardButtons buttons);
+ Q_INVOKABLE QQuickAbstractButton *standardButton(QPlatformDialogHelper::StandardButton button) const;
+
+ QQmlComponent *delegate() const;
+ void setDelegate(QQmlComponent *delegate);
+
+ static QQuickDialogButtonBoxAttached *qmlAttachedProperties(QObject *object);
+
+Q_SIGNALS:
+ void accepted();
+ void rejected();
+ void helpRequested();
+ void clicked(QQuickAbstractButton *button);
+
+ void positionChanged();
+ void alignmentChanged();
+ void standardButtonsChanged();
+ void delegateChanged();
+
+protected:
+ void updatePolish() override;
+ void componentComplete() override;
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override;
+ bool isContent(QQuickItem *item) const override;
+ void itemAdded(int index, QQuickItem *item) override;
+ void itemRemoved(int index, QQuickItem *item) override;
+
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickDialogButtonBox)
+ Q_DECLARE_PRIVATE(QQuickDialogButtonBox)
+};
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickDialogButtonBoxAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickDialogButtonBox *buttonBox READ buttonBox NOTIFY buttonBoxChanged FINAL)
+ Q_PROPERTY(QPlatformDialogHelper::ButtonRole buttonRole READ buttonRole WRITE setButtonRole NOTIFY buttonRoleChanged FINAL)
+ Q_ENUMS(QPlatformDialogHelper::ButtonRole)
+
+public:
+ explicit QQuickDialogButtonBoxAttached(QObject *parent = nullptr);
+
+ QQuickDialogButtonBox *buttonBox() const;
+
+ QPlatformDialogHelper::ButtonRole buttonRole() const;
+ void setButtonRole(QPlatformDialogHelper::ButtonRole role);
+
+Q_SIGNALS:
+ void buttonBoxChanged();
+ void buttonRoleChanged();
+
+private:
+ Q_DISABLE_COPY(QQuickDialogButtonBoxAttached)
+ Q_DECLARE_PRIVATE(QQuickDialogButtonBoxAttached)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickDialogButtonBox)
+QML_DECLARE_TYPEINFO(QQuickDialogButtonBox, QML_HAS_ATTACHED_PROPERTIES)
+
+#endif // QQUICKDIALOGBUTTONBOX_P_H
diff --git a/src/quicktemplates2/qquickdialogbuttonbox_p_p.h b/src/quicktemplates2/qquickdialogbuttonbox_p_p.h
new file mode 100644
index 00000000..d25bd90a
--- /dev/null
+++ b/src/quicktemplates2/qquickdialogbuttonbox_p_p.h
@@ -0,0 +1,107 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDIALOGBUTTONBOX_P_P_H
+#define QQUICKDIALOGBUTTONBOX_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuickTemplates2/private/qquickcontainer_p_p.h>
+#include <QtQuickTemplates2/private/qquickdialogbuttonbox_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickDialogButtonBoxPrivate : public QQuickContainerPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickDialogButtonBox)
+
+public:
+ QQuickDialogButtonBoxPrivate();
+
+ static QQuickDialogButtonBoxPrivate *get(QQuickDialogButtonBox *box)
+ {
+ return box->d_func();
+ }
+
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+
+ void resizeContent() override;
+ void updateLayout();
+ void handleClick();
+
+ QQuickAbstractButton *createStandardButton(QPlatformDialogHelper::StandardButton button);
+ void removeStandardButtons();
+
+ Qt::Alignment alignment;
+ QQuickDialogButtonBox::Position position;
+ QPlatformDialogHelper::StandardButtons standardButtons;
+ QQmlComponent *delegate;
+};
+
+class QQuickDialogButtonBoxAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickDialogButtonBoxAttached)
+
+public:
+ QQuickDialogButtonBoxAttachedPrivate() : buttonBox(nullptr),
+ buttonRole(QPlatformDialogHelper::InvalidRole),
+ standardButton(QPlatformDialogHelper::NoButton) { }
+
+ static QQuickDialogButtonBoxAttachedPrivate *get(QQuickDialogButtonBoxAttached *q)
+ {
+ return q->d_func();
+ }
+
+ void setButtonBox(QQuickDialogButtonBox *box);
+
+ QQuickDialogButtonBox *buttonBox;
+ QPlatformDialogHelper::ButtonRole buttonRole;
+ QPlatformDialogHelper::StandardButton standardButton;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKDIALOGBUTTONBOX_P_P_H
diff --git a/src/quicktemplates2/qquickdrawer.cpp b/src/quicktemplates2/qquickdrawer.cpp
index fe0a3c72..fbc871f7 100644
--- a/src/quicktemplates2/qquickdrawer.cpp
+++ b/src/quicktemplates2/qquickdrawer.cpp
@@ -76,7 +76,7 @@ QT_BEGIN_NAMESPACE
\code
import QtQuick 2.7
- import QtQuick.Controls 2.0
+ import QtQuick.Controls 2.1
ApplicationWindow {
id: window
diff --git a/src/quicktemplates2/qquickmenu.cpp b/src/quicktemplates2/qquickmenu.cpp
index f4fb26e7..ca18111c 100644
--- a/src/quicktemplates2/qquickmenu.cpp
+++ b/src/quicktemplates2/qquickmenu.cpp
@@ -201,7 +201,7 @@ void QQuickMenuPrivate::itemDestroyed(QQuickItem *item)
removeItem(index, item);
}
-void QQuickMenuPrivate::itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &)
+void QQuickMenuPrivate::itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &)
{
if (complete)
resizeItems();
diff --git a/src/quicktemplates2/qquickmenu_p_p.h b/src/quicktemplates2/qquickmenu_p_p.h
index 64260508..4137112d 100644
--- a/src/quicktemplates2/qquickmenu_p_p.h
+++ b/src/quicktemplates2/qquickmenu_p_p.h
@@ -77,7 +77,7 @@ public:
void itemSiblingOrderChanged(QQuickItem *item) override;
void itemParentChanged(QQuickItem *item, QQuickItem *parent) override;
void itemDestroyed(QQuickItem *item) override;
- void itemGeometryChanged(QQuickItem *, const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange change, const QRectF &diff) override;
void onItemPressed();
void onItemActiveFocusChanged();
diff --git a/src/quicktemplates2/qquickmenuseparator.cpp b/src/quicktemplates2/qquickmenuseparator.cpp
new file mode 100644
index 00000000..9aea6a91
--- /dev/null
+++ b/src/quicktemplates2/qquickmenuseparator.cpp
@@ -0,0 +1,80 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickmenuseparator_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype MenuSeparator
+ \inherits Control
+ \instantiates QQuickMenuSeparator
+ \inqmlmodule QtQuick.Controls
+ \since 5.8
+ \ingroup qtquickcontrols2-separators
+ \brief Separates a group of items in a menu from adjacent items.
+
+ MenuSeparator is used to visually distinguish between groups of items in a
+ menu by separating them with a line.
+
+ \image qtquickcontrols2-menuseparator.png
+
+ \quotefromfile qtquickcontrols2-menuseparator-custom.qml
+ \skipto import QtQuick 2.6
+ \printuntil import QtQuick.Controls 2.1
+ \skipto Menu
+ \printto contentItem.parent: window
+ \skipline contentItem.parent: window
+ \printuntil text: qsTr("Exit")
+ \printuntil }
+ \printuntil }
+
+ \sa {Customizing MenuSeparator}, {Separator Controls}
+*/
+
+QQuickMenuSeparator::QQuickMenuSeparator(QQuickItem *parent) :
+ QQuickControl(parent)
+{
+}
+
+#ifndef QT_NO_ACCESSIBILITY
+QAccessible::Role QQuickMenuSeparator::accessibleRole() const
+{
+ return QAccessible::Separator;
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickmenuseparator_p.h b/src/quicktemplates2/qquickmenuseparator_p.h
new file mode 100644
index 00000000..95a8f8fa
--- /dev/null
+++ b/src/quicktemplates2/qquickmenuseparator_p.h
@@ -0,0 +1,75 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKMENUSEPARATOR_P_H
+#define QQUICKMENUSEPARATOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickMenuSeparator : public QQuickControl
+{
+ Q_OBJECT
+
+public:
+ explicit QQuickMenuSeparator(QQuickItem *parent = nullptr);
+
+protected:
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickMenuSeparator)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickMenuSeparator)
+
+#endif // QQUICKMENUSEPARATOR_P_H
diff --git a/src/quicktemplates2/qquickpage.cpp b/src/quicktemplates2/qquickpage.cpp
index 5c2c5b42..4304c4fb 100644
--- a/src/quicktemplates2/qquickpage.cpp
+++ b/src/quicktemplates2/qquickpage.cpp
@@ -36,10 +36,7 @@
#include "qquickpage_p.h"
#include "qquickcontrol_p_p.h"
-#include "qquicktoolbar_p.h"
-#include "qquicktabbar_p.h"
-
-#include <QtQuick/private/qquickitemchangelistener_p.h>
+#include "qquickpagelayout_p_p.h"
QT_BEGIN_NAMESPACE
@@ -61,7 +58,7 @@ QT_BEGIN_NAMESPACE
toolbar header and an application-wide tabbar footer.
\qml
- import QtQuick.Controls 2.0
+ import QtQuick.Controls 2.1
ApplicationWindow {
visible: true
@@ -85,81 +82,22 @@ QT_BEGIN_NAMESPACE
\sa ApplicationWindow, {Container Controls}
*/
-class QQuickPagePrivate : public QQuickControlPrivate, public QQuickItemChangeListener
+class QQuickPagePrivate : public QQuickControlPrivate
{
Q_DECLARE_PUBLIC(QQuickPage)
public:
- QQuickPagePrivate();
-
- void relayout();
-
- void itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect) override;
- void itemVisibilityChanged(QQuickItem *item) override;
- void itemImplicitWidthChanged(QQuickItem *item) override;
- void itemImplicitHeightChanged(QQuickItem *item) override;
-
QString title;
- QQuickItem *header;
- QQuickItem *footer;
+ QScopedPointer<QQuickPageLayout> layout;
};
-QQuickPagePrivate::QQuickPagePrivate() : header(nullptr), footer(nullptr)
-{
-}
-
-void QQuickPagePrivate::relayout()
-{
- Q_Q(QQuickPage);
- QQuickItem *content = q->contentItem();
- const qreal hh = header && header->isVisible() ? header->height() : 0;
- const qreal fh = footer && footer->isVisible() ? footer->height() : 0;
-
- content->setY(hh + q->topPadding());
- content->setX(q->leftPadding());
- content->setWidth(q->availableWidth());
- content->setHeight(q->availableHeight() - hh - fh);
-
- if (header)
- header->setWidth(q->width());
-
- if (footer) {
- footer->setY(q->height() - fh);
- footer->setWidth(q->width());
- }
-}
-
-void QQuickPagePrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newRect, const QRectF &oldRect)
-{
- Q_UNUSED(item)
- Q_UNUSED(newRect)
- Q_UNUSED(oldRect)
- relayout();
-}
-
-void QQuickPagePrivate::itemVisibilityChanged(QQuickItem *item)
-{
- Q_UNUSED(item);
- relayout();
-}
-
-void QQuickPagePrivate::itemImplicitWidthChanged(QQuickItem *item)
-{
- Q_UNUSED(item);
- relayout();
-}
-
-void QQuickPagePrivate::itemImplicitHeightChanged(QQuickItem *item)
-{
- Q_UNUSED(item);
- relayout();
-}
-
QQuickPage::QQuickPage(QQuickItem *parent) :
QQuickControl(*(new QQuickPagePrivate), parent)
{
+ Q_D(QQuickPage);
setFlag(ItemIsFocusScope);
setAcceptedMouseButtons(Qt::AllButtons);
+ d->layout.reset(new QQuickPageLayout(this));
}
/*!
@@ -189,43 +127,25 @@ void QQuickPage::setTitle(const QString &title)
This property holds the page header item. The header item is positioned to
the top, and resized to the width of the page. The default value is \c null.
- \note Assigning a ToolBar or TabBar as a page header sets the respective
- \l ToolBar::position or \l TabBar::position property automatically to \c Header.
+ \note Assigning a ToolBar, TabBar, or DialogButtonBox as a page header
+ automatically sets the respective \l ToolBar::position, \l TabBar::position,
+ or \l DialogButtonBox::position property to \c Header.
\sa footer, ApplicationWindow::header
*/
QQuickItem *QQuickPage::header() const
{
Q_D(const QQuickPage);
- return d->header;
+ return d->layout->header();
}
void QQuickPage::setHeader(QQuickItem *header)
{
Q_D(QQuickPage);
- if (d->header == header)
+ if (!d->layout->setHeader(header))
return;
-
- if (d->header) {
- QQuickItemPrivate::get(d->header)->removeItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility |
- QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
- d->header->setParentItem(nullptr);
- }
- d->header = header;
- if (header) {
- header->setParentItem(this);
- QQuickItemPrivate *p = QQuickItemPrivate::get(header);
- p->addItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility |
- QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
- if (qFuzzyIsNull(header->z()))
- header->setZ(1);
- if (QQuickToolBar *toolBar = qobject_cast<QQuickToolBar *>(header))
- toolBar->setPosition(QQuickToolBar::Header);
- else if (QQuickTabBar *tabBar = qobject_cast<QQuickTabBar *>(header))
- tabBar->setPosition(QQuickTabBar::Header);
- }
if (isComponentComplete())
- d->relayout();
+ d->layout->update();
emit headerChanged();
}
@@ -235,43 +155,25 @@ void QQuickPage::setHeader(QQuickItem *header)
This property holds the page footer item. The footer item is positioned to
the bottom, and resized to the width of the page. The default value is \c null.
- \note Assigning a ToolBar or TabBar as a page footer sets the respective
- \l ToolBar::position or \l TabBar::position property automatically to \c Footer.
+ \note Assigning a ToolBar, TabBar, or DialogButtonBox as a page footer
+ automatically sets the respective \l ToolBar::position, \l TabBar::position,
+ or \l DialogButtonBox::position property to \c Footer.
\sa header, ApplicationWindow::footer
*/
QQuickItem *QQuickPage::footer() const
{
Q_D(const QQuickPage);
- return d->footer;
+ return d->layout->footer();
}
void QQuickPage::setFooter(QQuickItem *footer)
{
Q_D(QQuickPage);
- if (d->footer == footer)
+ if (!d->layout->setFooter(footer))
return;
-
- if (d->footer) {
- QQuickItemPrivate::get(d->footer)->removeItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility |
- QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
- d->footer->setParentItem(nullptr);
- }
- d->footer = footer;
- if (footer) {
- footer->setParentItem(this);
- QQuickItemPrivate *p = QQuickItemPrivate::get(footer);
- p->addItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility |
- QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight);
- if (qFuzzyIsNull(footer->z()))
- footer->setZ(1);
- if (QQuickToolBar *toolBar = qobject_cast<QQuickToolBar *>(footer))
- toolBar->setPosition(QQuickToolBar::Footer);
- else if (QQuickTabBar *tabBar = qobject_cast<QQuickTabBar *>(footer))
- tabBar->setPosition(QQuickTabBar::Footer);
- }
if (isComponentComplete())
- d->relayout();
+ d->layout->update();
emit footerChanged();
}
@@ -324,14 +226,14 @@ void QQuickPage::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeo
{
Q_D(QQuickPage);
QQuickControl::geometryChanged(newGeometry, oldGeometry);
- d->relayout();
+ d->layout->update();
}
void QQuickPage::paddingChange(const QMarginsF &newPadding, const QMarginsF &oldPadding)
{
Q_D(QQuickPage);
QQuickControl::paddingChange(newPadding, oldPadding);
- d->relayout();
+ d->layout->update();
}
#ifndef QT_NO_ACCESSIBILITY
diff --git a/src/quicktemplates2/qquickpagelayout.cpp b/src/quicktemplates2/qquickpagelayout.cpp
new file mode 100644
index 00000000..a1747b47
--- /dev/null
+++ b/src/quicktemplates2/qquickpagelayout.cpp
@@ -0,0 +1,188 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickpagelayout_p_p.h"
+#include "qquickcontrol_p.h"
+#include "qquicktoolbar_p.h"
+#include "qquicktabbar_p.h"
+#include "qquickdialogbuttonbox_p.h"
+
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+static const QQuickItemPrivate::ChangeTypes ItemChanges = QQuickItemPrivate::Geometry | QQuickItemPrivate::Visibility | QQuickItemPrivate::Destroyed
+ | QQuickItemPrivate::ImplicitWidth | QQuickItemPrivate::ImplicitHeight;
+
+namespace {
+ enum Position {
+ Header,
+ Footer
+ };
+
+ Q_STATIC_ASSERT(int(Header) == int(QQuickTabBar::Header));
+ Q_STATIC_ASSERT(int(Footer) == int(QQuickTabBar::Footer));
+
+ Q_STATIC_ASSERT(int(Header) == int(QQuickToolBar::Header));
+ Q_STATIC_ASSERT(int(Footer) == int(QQuickToolBar::Footer));
+
+ Q_STATIC_ASSERT(int(Header) == int(QQuickDialogButtonBox::Header));
+ Q_STATIC_ASSERT(int(Footer) == int(QQuickDialogButtonBox::Footer));
+}
+
+static void setPosition(QQuickItem *item, Position position)
+{
+ if (QQuickToolBar *toolBar = qobject_cast<QQuickToolBar *>(item))
+ toolBar->setPosition(static_cast<QQuickToolBar::Position>(position));
+ else if (QQuickTabBar *tabBar = qobject_cast<QQuickTabBar *>(item))
+ tabBar->setPosition(static_cast<QQuickTabBar::Position>(position));
+ else if (QQuickDialogButtonBox *buttonBox = qobject_cast<QQuickDialogButtonBox *>(item))
+ buttonBox->setPosition(static_cast<QQuickDialogButtonBox::Position>(position));
+}
+
+QQuickPageLayout::QQuickPageLayout(QQuickControl *control)
+ : m_header(nullptr), m_footer(nullptr), m_control(control)
+{
+}
+
+QQuickPageLayout::~QQuickPageLayout()
+{
+ if (m_header)
+ QQuickItemPrivate::get(m_header)->removeItemChangeListener(this, ItemChanges);
+ if (m_footer)
+ QQuickItemPrivate::get(m_footer)->removeItemChangeListener(this, ItemChanges);
+}
+
+QQuickItem *QQuickPageLayout::header() const
+{
+ return m_header;
+}
+
+bool QQuickPageLayout::setHeader(QQuickItem *header)
+{
+ if (m_header == header)
+ return false;
+
+ if (m_header) {
+ QQuickItemPrivate::get(m_header)->removeItemChangeListener(this, ItemChanges);
+ m_header->setParentItem(nullptr);
+ }
+ m_header = header;
+ if (header) {
+ header->setParentItem(m_control);
+ QQuickItemPrivate::get(header)->addItemChangeListener(this, ItemChanges);
+ if (qFuzzyIsNull(header->z()))
+ header->setZ(1);
+ setPosition(header, Header);
+ }
+ return true;
+}
+
+QQuickItem *QQuickPageLayout::footer() const
+{
+ return m_footer;
+}
+
+bool QQuickPageLayout::setFooter(QQuickItem *footer)
+{
+ if (m_footer == footer)
+ return false;
+
+ if (m_footer) {
+ QQuickItemPrivate::get(m_footer)->removeItemChangeListener(this, ItemChanges);
+ m_footer->setParentItem(nullptr);
+ }
+ m_footer = footer;
+ if (footer) {
+ footer->setParentItem(m_control);
+ QQuickItemPrivate::get(footer)->addItemChangeListener(this, ItemChanges);
+ if (qFuzzyIsNull(footer->z()))
+ footer->setZ(1);
+ setPosition(footer, Footer);
+ }
+ return true;
+}
+
+void QQuickPageLayout::update()
+{
+ QQuickItem *content = m_control->contentItem();
+
+ const qreal hh = m_header && m_header->isVisible() ? m_header->height() : 0;
+ const qreal fh = m_footer && m_footer->isVisible() ? m_footer->height() : 0;
+
+ content->setY(hh + m_control->topPadding());
+ content->setX(m_control->leftPadding());
+ content->setWidth(m_control->availableWidth());
+ content->setHeight(m_control->availableHeight() - hh - fh);
+
+ if (m_header)
+ m_header->setWidth(m_control->width());
+
+ if (m_footer) {
+ m_footer->setY(m_control->height() - fh);
+ m_footer->setWidth(m_control->width());
+ }
+}
+
+void QQuickPageLayout::itemVisibilityChanged(QQuickItem *)
+{
+ update();
+}
+
+void QQuickPageLayout::itemImplicitWidthChanged(QQuickItem *)
+{
+ update();
+}
+
+void QQuickPageLayout::itemImplicitHeightChanged(QQuickItem *)
+{
+ update();
+}
+
+void QQuickPageLayout::itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &)
+{
+ update();
+}
+
+void QQuickPageLayout::itemDestroyed(QQuickItem *item)
+{
+ if (item == m_header)
+ m_header = nullptr;
+ else if (item == m_footer)
+ m_footer = nullptr;
+}
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickpagelayout_p_p.h b/src/quicktemplates2/qquickpagelayout_p_p.h
new file mode 100644
index 00000000..fbeaa877
--- /dev/null
+++ b/src/quicktemplates2/qquickpagelayout_p_p.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKPAGELAYOUT_P_P_H
+#define QQUICKPAGELAYOUT_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickControl;
+
+class QQuickPageLayout : public QQuickItemChangeListener
+{
+public:
+ explicit QQuickPageLayout(QQuickControl *control);
+ ~QQuickPageLayout();
+
+ QQuickItem *header() const;
+ bool setHeader(QQuickItem *header);
+
+ QQuickItem *footer() const;
+ bool setFooter(QQuickItem *footer);
+
+ void update();
+
+protected:
+ void itemVisibilityChanged(QQuickItem *item) override;
+ void itemImplicitWidthChanged(QQuickItem *item) override;
+ void itemImplicitHeightChanged(QQuickItem *item) override;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
+ void itemDestroyed(QQuickItem *item) override;
+
+private:
+ QQuickItem *m_header;
+ QQuickItem *m_footer;
+ QQuickControl *m_control;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKPAGELAYOUT_P_P_H
diff --git a/src/quicktemplates2/qquickpopup.cpp b/src/quicktemplates2/qquickpopup.cpp
index 57087c0a..14810c98 100644
--- a/src/quicktemplates2/qquickpopup.cpp
+++ b/src/quicktemplates2/qquickpopup.cpp
@@ -61,7 +61,7 @@ QT_BEGIN_NAMESPACE
\qml
import QtQuick.Window 2.2
- import QtQuick.Controls 2.0
+ import QtQuick.Controls 2.1
Window {
id: window
@@ -534,7 +534,7 @@ void QQuickPopupPositioner::setParentItem(QQuickItem *parent)
m_popup->reposition();
}
-void QQuickPopupPositioner::itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &)
+void QQuickPopupPositioner::itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &)
{
if (m_parentItem && m_popup->popupItem->isVisible())
m_popup->reposition();
@@ -1329,6 +1329,64 @@ void QQuickPopup::resetBottomPadding()
}
/*!
+ \since QtQuick.Controls 2.1
+ \qmlproperty bool QtQuick.Controls::Popup::allowVerticalFlip
+
+ This property holds whether the popup is allowed to flip vertically.
+
+ A popup can be flipped from above its parent item to below it, or vice
+ versa, in order to make the popup fit inside the window.
+
+ The default value is \c false.
+
+ \sa allowHorizontalFlip
+*/
+bool QQuickPopup::allowVerticalFlip() const
+{
+ Q_D(const QQuickPopup);
+ return d->allowVerticalFlip;
+}
+
+void QQuickPopup::setAllowVerticalFlip(bool allow)
+{
+ Q_D(QQuickPopup);
+ if (d->allowVerticalFlip == allow)
+ return;
+
+ d->allowVerticalFlip = allow;
+ emit allowVerticalFlipChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.1
+ \qmlproperty bool QtQuick.Controls::Popup::allowHorizontalFlip
+
+ This property holds whether the popup is allowed to flip horizontally.
+
+ A popup can be flipped from the left side of its parent item to the right
+ side, or vice versa, in order to make the popup fit inside the window.
+
+ The default value is \c false.
+
+ \sa allowVerticalFlip
+*/
+bool QQuickPopup::allowHorizontalFlip() const
+{
+ Q_D(const QQuickPopup);
+ return d->allowHorizontalFlip;
+}
+
+void QQuickPopup::setAllowHorizontalFlip(bool allow)
+{
+ Q_D(QQuickPopup);
+ if (d->allowHorizontalFlip == allow)
+ return;
+
+ d->allowHorizontalFlip = allow;
+ emit allowHorizontalFlipChanged();
+}
+
+/*!
\qmlproperty Locale QtQuick.Controls::Popup::locale
This property holds the locale of the popup.
diff --git a/src/quicktemplates2/qquickpopup_p.h b/src/quicktemplates2/qquickpopup_p.h
index be6a8e22..1f2cabcf 100644
--- a/src/quicktemplates2/qquickpopup_p.h
+++ b/src/quicktemplates2/qquickpopup_p.h
@@ -94,6 +94,8 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickPopup : public QObject, public QQml
Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged FINAL)
Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged FINAL)
Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged FINAL)
+ Q_PROPERTY(bool allowVerticalFlip READ allowVerticalFlip WRITE setAllowVerticalFlip NOTIFY allowVerticalFlipChanged FINAL REVISION 1)
+ Q_PROPERTY(bool allowHorizontalFlip READ allowHorizontalFlip WRITE setAllowHorizontalFlip NOTIFY allowHorizontalFlipChanged FINAL REVISION 1)
Q_PROPERTY(QLocale locale READ locale WRITE setLocale RESET resetLocale NOTIFY localeChanged FINAL)
Q_PROPERTY(QFont font READ font WRITE setFont RESET resetFont NOTIFY fontChanged FINAL)
Q_PROPERTY(QQuickItem *parent READ parentItem WRITE setParentItem NOTIFY parentChanged FINAL)
@@ -194,6 +196,12 @@ public:
void setBottomPadding(qreal padding);
void resetBottomPadding();
+ bool allowVerticalFlip() const;
+ void setAllowVerticalFlip(bool allow);
+
+ bool allowHorizontalFlip() const;
+ void setAllowHorizontalFlip(bool allow);
+
QLocale locale() const;
void setLocale(const QLocale &locale);
void resetLocale();
@@ -303,6 +311,8 @@ Q_SIGNALS:
void leftPaddingChanged();
void rightPaddingChanged();
void bottomPaddingChanged();
+ Q_REVISION(1) void allowVerticalFlipChanged();
+ Q_REVISION(1) void allowHorizontalFlipChanged();
void fontChanged();
void localeChanged();
void parentChanged();
diff --git a/src/quicktemplates2/qquickpopup_p_p.h b/src/quicktemplates2/qquickpopup_p_p.h
index ffe2c2bb..342fecaf 100644
--- a/src/quicktemplates2/qquickpopup_p_p.h
+++ b/src/quicktemplates2/qquickpopup_p_p.h
@@ -133,7 +133,7 @@ public:
void setParentItem(QQuickItem *parent);
protected:
- void itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &);
+ void itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &);
void itemParentChanged(QQuickItem *, QQuickItem *parent);
void itemChildRemoved(QQuickItem *, QQuickItem *child);
void itemDestroyed(QQuickItem *item);
diff --git a/src/quicktemplates2/qquickpresshandler.cpp b/src/quicktemplates2/qquickpresshandler.cpp
index 1e1a17bc..5c868ee2 100644
--- a/src/quicktemplates2/qquickpresshandler.cpp
+++ b/src/quicktemplates2/qquickpresshandler.cpp
@@ -48,6 +48,8 @@ QQuickPressHandler::QQuickPressHandler()
: control(nullptr)
, longPress(false)
, pressAndHoldSignalIndex(-1)
+ , pressedSignalIndex(-1)
+ , releasedSignalIndex(-1)
, delayedMousePressEvent(nullptr)
{ }
@@ -61,6 +63,21 @@ void QQuickPressHandler::mousePressEvent(QMouseEvent *event)
} else {
timer.stop();
}
+
+ if (pressedSignalIndex == -1)
+ pressedSignalIndex = control->metaObject()->indexOfSignal("pressed(QQuickMouseEvent*)");
+ Q_ASSERT(pressedSignalIndex != -1);
+
+ if (QObjectPrivate::get(control)->isSignalConnected(pressedSignalIndex)) {
+ QQuickMouseEvent mev;
+ mev.reset(pressPos.x(), pressPos.y(), event->button(), event->buttons(),
+ QGuiApplication::keyboardModifiers(), false/*isClick*/, false/*wasHeld*/);
+ mev.setAccepted(true);
+ QQuickMouseEvent *mevPtr = &mev;
+ void *args[] = { nullptr, &mevPtr };
+ QMetaObject::metacall(control, QMetaObject::InvokeMetaMethod, pressedSignalIndex, args);
+ event->setAccepted(mev.isAccepted());
+ }
}
void QQuickPressHandler::mouseMoveEvent(QMouseEvent *event)
@@ -69,10 +86,26 @@ void QQuickPressHandler::mouseMoveEvent(QMouseEvent *event)
timer.stop();
}
-void QQuickPressHandler::mouseReleaseEvent(QMouseEvent *)
+void QQuickPressHandler::mouseReleaseEvent(QMouseEvent *event)
{
- if (!longPress)
+ if (!longPress) {
timer.stop();
+
+ if (releasedSignalIndex == -1)
+ releasedSignalIndex = control->metaObject()->indexOfSignal("released(QQuickMouseEvent*)");
+ Q_ASSERT(releasedSignalIndex != -1);
+
+ if (QObjectPrivate::get(control)->isSignalConnected(releasedSignalIndex)) {
+ QQuickMouseEvent mev;
+ mev.reset(pressPos.x(), pressPos.y(), event->button(), event->buttons(),
+ QGuiApplication::keyboardModifiers(), false/*isClick*/, false/*wasHeld*/);
+ mev.setAccepted(true);
+ QQuickMouseEvent *mevPtr = &mev;
+ void *args[] = { nullptr, &mevPtr };
+ QMetaObject::metacall(control, QMetaObject::InvokeMetaMethod, releasedSignalIndex, args);
+ event->setAccepted(mev.isAccepted());
+ }
+ }
}
void QQuickPressHandler::timerEvent(QTimerEvent *)
@@ -86,8 +119,9 @@ void QQuickPressHandler::timerEvent(QTimerEvent *)
longPress = QObjectPrivate::get(control)->isSignalConnected(pressAndHoldSignalIndex);
if (longPress) {
- QQuickMouseEvent mev(pressPos.x(), pressPos.y(), Qt::LeftButton, Qt::LeftButton,
- QGuiApplication::keyboardModifiers(), false/*isClick*/, true/*wasHeld*/);
+ QQuickMouseEvent mev;
+ mev.reset(pressPos.x(), pressPos.y(), Qt::LeftButton, Qt::LeftButton,
+ QGuiApplication::keyboardModifiers(), false/*isClick*/, true/*wasHeld*/);
mev.setAccepted(true);
// Use fast signal invocation since we already got its index
QQuickMouseEvent *mevPtr = &mev;
diff --git a/src/quicktemplates2/qquickpresshandler_p_p.h b/src/quicktemplates2/qquickpresshandler_p_p.h
index dec6f202..e432fe10 100644
--- a/src/quicktemplates2/qquickpresshandler_p_p.h
+++ b/src/quicktemplates2/qquickpresshandler_p_p.h
@@ -74,6 +74,8 @@ struct QQuickPressHandler
QPointF pressPos;
bool longPress;
int pressAndHoldSignalIndex;
+ int pressedSignalIndex;
+ int releasedSignalIndex;
QMouseEvent *delayedMousePressEvent;
};
diff --git a/src/quicktemplates2/qquickrangeslider.cpp b/src/quicktemplates2/qquickrangeslider.cpp
index bdae85b1..b4c3838f 100644
--- a/src/quicktemplates2/qquickrangeslider.cpp
+++ b/src/quicktemplates2/qquickrangeslider.cpp
@@ -88,7 +88,8 @@ public:
position(0),
handle(nullptr),
slider(slider),
- pressed(false)
+ pressed(false),
+ hovered(false)
{
}
@@ -109,6 +110,7 @@ private:
QQuickItem *handle;
QQuickRangeSlider *slider;
bool pressed;
+ bool hovered;
};
bool QQuickRangeSliderNodePrivate::isFirst() const
@@ -272,6 +274,22 @@ void QQuickRangeSliderNode::setPressed(bool pressed)
emit pressedChanged();
}
+bool QQuickRangeSliderNode::isHovered() const
+{
+ Q_D(const QQuickRangeSliderNode);
+ return d->hovered;
+}
+
+void QQuickRangeSliderNode::setHovered(bool hovered)
+{
+ Q_D(QQuickRangeSliderNode);
+ if (d->hovered == hovered)
+ return;
+
+ d->hovered = hovered;
+ emit hoveredChanged();
+}
+
void QQuickRangeSliderNode::increase()
{
Q_D(QQuickRangeSliderNode);
@@ -305,6 +323,8 @@ public:
{
}
+ void updateHover(const QPointF &pos);
+
qreal from;
qreal to;
qreal stepSize;
@@ -315,6 +335,15 @@ public:
QQuickRangeSlider::SnapMode snapMode;
};
+void QQuickRangeSliderPrivate::updateHover(const QPointF &pos)
+{
+ Q_Q(QQuickRangeSlider);
+ QQuickItem *firstHandle = first->handle();
+ QQuickItem *secondHandle = second->handle();
+ first->setHovered(firstHandle && firstHandle->isEnabled() && firstHandle->contains(q->mapToItem(firstHandle, pos)));
+ second->setHovered(secondHandle && secondHandle->isEnabled() && secondHandle->contains(q->mapToItem(secondHandle, pos)));
+}
+
static qreal valueAt(const QQuickRangeSlider *slider, qreal position)
{
return slider->from() + (slider->to() - slider->from()) * position;
@@ -428,6 +457,7 @@ void QQuickRangeSlider::setTo(qreal to)
\qmlproperty real QtQuick.Controls::RangeSlider::first.visualPosition
\qmlproperty Item QtQuick.Controls::RangeSlider::first.handle
\qmlproperty bool QtQuick.Controls::RangeSlider::first.pressed
+ \qmlproperty bool QtQuick.Controls::RangeSlider::first.hovered
\table
\header
@@ -468,6 +498,10 @@ void QQuickRangeSlider::setTo(qreal to)
\row
\li pressed
\li This property holds whether the first handle is pressed.
+ \row
+ \li hovered
+ \li This property holds whether the first handle is hovered.
+ This property was introduced in QtQuick.Controls 2.1.
\endtable
\sa first.increase(), first.decrease()
@@ -485,6 +519,7 @@ QQuickRangeSliderNode *QQuickRangeSlider::first() const
\qmlproperty real QtQuick.Controls::RangeSlider::second.visualPosition
\qmlproperty Item QtQuick.Controls::RangeSlider::second.handle
\qmlproperty bool QtQuick.Controls::RangeSlider::second.pressed
+ \qmlproperty bool QtQuick.Controls::RangeSlider::second.hovered
\table
\header
@@ -525,6 +560,10 @@ QQuickRangeSliderNode *QQuickRangeSlider::first() const
\row
\li pressed
\li This property holds whether the second handle is pressed.
+ \row
+ \li hovered
+ \li This property holds whether the second handle is hovered.
+ This property was introduced in QtQuick.Controls 2.1.
\endtable
\sa second.increase(), second.decrease()
@@ -725,6 +764,28 @@ void QQuickRangeSlider::keyPressEvent(QKeyEvent *event)
}
}
+void QQuickRangeSlider::hoverEnterEvent(QHoverEvent *event)
+{
+ Q_D(QQuickRangeSlider);
+ QQuickControl::hoverEnterEvent(event);
+ d->updateHover(event->posF());
+}
+
+void QQuickRangeSlider::hoverMoveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickRangeSlider);
+ QQuickControl::hoverMoveEvent(event);
+ d->updateHover(event->posF());
+}
+
+void QQuickRangeSlider::hoverLeaveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickRangeSlider);
+ QQuickControl::hoverLeaveEvent(event);
+ d->first->setHovered(false);
+ d->second->setHovered(false);
+}
+
void QQuickRangeSlider::keyReleaseEvent(QKeyEvent *event)
{
Q_D(QQuickRangeSlider);
diff --git a/src/quicktemplates2/qquickrangeslider_p.h b/src/quicktemplates2/qquickrangeslider_p.h
index 4c2eb4bb..1b102e87 100644
--- a/src/quicktemplates2/qquickrangeslider_p.h
+++ b/src/quicktemplates2/qquickrangeslider_p.h
@@ -105,6 +105,9 @@ Q_SIGNALS:
protected:
void focusInEvent(QFocusEvent *event) override;
+ void hoverEnterEvent(QHoverEvent *event) override;
+ void hoverMoveEvent(QHoverEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
@@ -135,6 +138,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickRangeSliderNode : public QObject
Q_PROPERTY(qreal visualPosition READ visualPosition NOTIFY visualPositionChanged FINAL)
Q_PROPERTY(QQuickItem *handle READ handle WRITE setHandle NOTIFY handleChanged FINAL)
Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL)
+ Q_PROPERTY(bool hovered READ isHovered WRITE setHovered NOTIFY hoveredChanged FINAL REVISION 1)
public:
explicit QQuickRangeSliderNode(qreal value, QQuickRangeSlider *slider);
@@ -152,6 +156,9 @@ public:
bool isPressed() const;
void setPressed(bool pressed);
+ bool isHovered() const;
+ void setHovered(bool hovered);
+
public Q_SLOTS:
void increase();
void decrease();
@@ -162,6 +169,7 @@ Q_SIGNALS:
void visualPositionChanged();
void handleChanged();
void pressedChanged();
+ Q_REVISION(1) void hoveredChanged();
private:
Q_DISABLE_COPY(QQuickRangeSliderNode)
diff --git a/src/quicktemplates2/qquickscrollbar.cpp b/src/quicktemplates2/qquickscrollbar.cpp
index c2506c3c..5f26814d 100644
--- a/src/quicktemplates2/qquickscrollbar.cpp
+++ b/src/quicktemplates2/qquickscrollbar.cpp
@@ -405,7 +405,7 @@ public:
void layoutHorizontal(bool move = true);
void layoutVertical(bool move = true);
- void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
void itemDestroyed(QQuickItem *item) override;
QQuickFlickable *flickable;
@@ -476,16 +476,16 @@ void QQuickScrollBarAttachedPrivate::layoutVertical(bool move)
vertical->setX(vertical->isMirrored() ? 0 : flickable->width() - vertical->width());
}
-void QQuickScrollBarAttachedPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
+void QQuickScrollBarAttachedPrivate::itemGeometryChanged(QQuickItem *item, const QQuickGeometryChange change, const QRectF &diff)
{
Q_UNUSED(item);
- Q_UNUSED(newGeometry);
+ Q_UNUSED(change);
if (horizontal && horizontal->height() > 0) {
- bool move = qFuzzyIsNull(horizontal->y()) || qFuzzyCompare(horizontal->y(), oldGeometry.height() - horizontal->height());
+ bool move = qFuzzyIsNull(horizontal->y()) || qFuzzyCompare(horizontal->y(), item->height() - diff.height() - horizontal->height());
layoutHorizontal(move);
}
if (vertical && vertical->width() > 0) {
- bool move = qFuzzyIsNull(vertical->x()) || qFuzzyCompare(vertical->x(), oldGeometry.width() - vertical->width());
+ bool move = qFuzzyIsNull(vertical->x()) || qFuzzyCompare(vertical->x(), item->width() - diff.width() - vertical->width());
layoutVertical(move);
}
}
@@ -504,7 +504,7 @@ QQuickScrollBarAttached::QQuickScrollBarAttached(QQuickFlickable *flickable) :
Q_D(QQuickScrollBarAttached);
if (flickable) {
QQuickItemPrivate *p = QQuickItemPrivate::get(flickable);
- p->updateOrAddGeometryChangeListener(d, QQuickItemPrivate::SizeChange);
+ p->updateOrAddGeometryChangeListener(d, QQuickGeometryChange::Size);
}
}
diff --git a/src/quicktemplates2/qquickscrollindicator.cpp b/src/quicktemplates2/qquickscrollindicator.cpp
index 55e86d87..acb8dd46 100644
--- a/src/quicktemplates2/qquickscrollindicator.cpp
+++ b/src/quicktemplates2/qquickscrollindicator.cpp
@@ -242,7 +242,7 @@ public:
void layoutHorizontal(bool move = true);
void layoutVertical(bool move = true);
- void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
void itemDestroyed(QQuickItem *item) override;
QQuickFlickable *flickable;
@@ -276,16 +276,16 @@ void QQuickScrollIndicatorAttachedPrivate::layoutVertical(bool move)
vertical->setX(flickable->width() - vertical->width());
}
-void QQuickScrollIndicatorAttachedPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
+void QQuickScrollIndicatorAttachedPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
{
Q_UNUSED(item);
- Q_UNUSED(newGeometry);
+ Q_UNUSED(change);
if (horizontal && horizontal->height() > 0) {
- bool move = qFuzzyIsNull(horizontal->y()) || qFuzzyCompare(horizontal->y(), oldGeometry.height() - horizontal->height());
+ bool move = qFuzzyIsNull(horizontal->y()) || qFuzzyCompare(horizontal->y(), item->height() - diff.height() - horizontal->height());
layoutHorizontal(move);
}
if (vertical && vertical->width() > 0) {
- bool move = qFuzzyIsNull(vertical->x()) || qFuzzyCompare(vertical->x(), oldGeometry.width() - vertical->width());
+ bool move = qFuzzyIsNull(vertical->x()) || qFuzzyCompare(vertical->x(), item->width() - diff.width() - vertical->width());
layoutVertical(move);
}
}
@@ -304,7 +304,7 @@ QQuickScrollIndicatorAttached::QQuickScrollIndicatorAttached(QQuickFlickable *fl
Q_D(QQuickScrollIndicatorAttached);
if (flickable) {
QQuickItemPrivate *p = QQuickItemPrivate::get(flickable);
- p->updateOrAddGeometryChangeListener(d, QQuickItemPrivate::SizeChange);
+ p->updateOrAddGeometryChangeListener(d, QQuickGeometryChange::Size);
}
}
diff --git a/src/quicktemplates2/qquickslider.cpp b/src/quicktemplates2/qquickslider.cpp
index bd68334e..2a89ab4f 100644
--- a/src/quicktemplates2/qquickslider.cpp
+++ b/src/quicktemplates2/qquickslider.cpp
@@ -83,7 +83,6 @@ public:
{
}
- qreal valueAt(qreal position) const;
qreal snapPosition(qreal position) const;
qreal positionAt(const QPoint &point) const;
void setPosition(qreal position);
@@ -101,11 +100,6 @@ public:
QQuickItem *handle;
};
-qreal QQuickSliderPrivate::valueAt(qreal position) const
-{
- return from + (to - from) * position;
-}
-
qreal QQuickSliderPrivate::snapPosition(qreal position) const
{
const qreal range = to - from;
@@ -229,10 +223,11 @@ void QQuickSlider::setTo(qreal to)
This property holds the value in the range \c from - \c to. The default value is \c 0.0.
Unlike the \l position property, the \c value is not updated while the
- handle is dragged. The value is updated after the value has been chosen
- and the slider has been released.
+ handle is dragged, but only after the value has been chosen and the slider
+ has been released. The \l valueAt() method can be used to get continuous
+ updates.
- \sa position
+ \sa position, valueAt()
*/
qreal QQuickSlider::value() const
{
@@ -265,7 +260,7 @@ void QQuickSlider::setValue(qreal value)
continuously updated while the handle is dragged. For visualizing a
slider, the right-to-left aware \l visualPosition should be used instead.
- \sa value, visualPosition
+ \sa value, visualPosition, valueAt()
*/
qreal QQuickSlider::position() const
{
@@ -419,6 +414,25 @@ void QQuickSlider::setHandle(QQuickItem *handle)
}
/*!
+ \since QtQuick.Controls 2.1
+ \qmlmethod real QtQuick.Controls::Slider::valueAt(real position)
+
+ Returns the value for the given \a position.
+
+ The \l value property is not updated while the handle is dragged, but this
+ method can be used to get continuous value updates:
+
+ \snippet qtquickcontrols2-tooltip-slider.qml 1
+
+ \sa value, position
+*/
+qreal QQuickSlider::valueAt(qreal position) const
+{
+ Q_D(const QQuickSlider);
+ return d->from + (d->to - d->from) * position;
+}
+
+/*!
\qmlmethod void QtQuick.Controls::Slider::increase()
Increases the value by \l stepSize or \c 0.1 if stepSize is not defined.
@@ -519,7 +533,7 @@ void QQuickSlider::mouseReleaseEvent(QMouseEvent *event)
qreal pos = d->positionAt(event->pos());
if (d->snapMode != NoSnap)
pos = d->snapPosition(pos);
- qreal val = d->valueAt(pos);
+ qreal val = valueAt(pos);
if (!qFuzzyCompare(val, d->value))
setValue(val);
else if (d->snapMode != NoSnap)
diff --git a/src/quicktemplates2/qquickslider_p.h b/src/quicktemplates2/qquickslider_p.h
index f6c1401a..d17af5c4 100644
--- a/src/quicktemplates2/qquickslider_p.h
+++ b/src/quicktemplates2/qquickslider_p.h
@@ -105,6 +105,8 @@ public:
QQuickItem *handle() const;
void setHandle(QQuickItem *handle);
+ Q_REVISION(1) Q_INVOKABLE qreal valueAt(qreal position) const;
+
public Q_SLOTS:
void increase();
void decrease();
diff --git a/src/quicktemplates2/qquickspinbox.cpp b/src/quicktemplates2/qquickspinbox.cpp
index b2d88d3b..634e3732 100644
--- a/src/quicktemplates2/qquickspinbox.cpp
+++ b/src/quicktemplates2/qquickspinbox.cpp
@@ -109,6 +109,7 @@ public:
void updateUpEnabled();
bool downEnabled() const;
void updateDownEnabled();
+ void updateHover(const QPointF &pos);
void startRepeatDelay();
void startPressRepeat();
@@ -190,6 +191,15 @@ void QQuickSpinBoxPrivate::updateDownEnabled()
downIndicator->setEnabled(from < to ? value > from : value < from);
}
+void QQuickSpinBoxPrivate::updateHover(const QPointF &pos)
+{
+ Q_Q(QQuickSpinBox);
+ QQuickItem *ui = up->indicator();
+ QQuickItem *di = down->indicator();
+ up->setHovered(ui && ui->isEnabled() && ui->contains(q->mapToItem(ui, pos)));
+ down->setHovered(di && di->isEnabled() && di->contains(q->mapToItem(di, pos)));
+}
+
void QQuickSpinBoxPrivate::startRepeatDelay()
{
Q_Q(QQuickSpinBox);
@@ -526,8 +536,10 @@ void QQuickSpinBox::setValueFromText(const QJSValue &callback)
\qmlpropertygroup QtQuick.Controls::SpinBox::up
\qmlproperty bool QtQuick.Controls::SpinBox::up.pressed
\qmlproperty Item QtQuick.Controls::SpinBox::up.indicator
+ \qmlproperty bool QtQuick.Controls::SpinBox::up.hovered
- These properties hold the up indicator item and whether it is pressed.
+ These properties hold the up indicator item and whether it is pressed or
+ hovered. The \c up.hovered property was introduced in QtQuick.Controls 2.1.
\sa increase()
*/
@@ -541,8 +553,10 @@ QQuickSpinButton *QQuickSpinBox::up() const
\qmlpropertygroup QtQuick.Controls::SpinBox::down
\qmlproperty bool QtQuick.Controls::SpinBox::down.pressed
\qmlproperty Item QtQuick.Controls::SpinBox::down.indicator
+ \qmlproperty bool QtQuick.Controls::SpinBox::down.hovered
- These properties hold the down indicator item and whether it is pressed.
+ These properties hold the down indicator item and whether it is pressed or
+ hovered. The \c down.hovered property was introduced in QtQuick.Controls 2.1.
\sa decrease()
*/
@@ -578,6 +592,28 @@ void QQuickSpinBox::decrease()
setValue(d->value - d->effectiveStepSize());
}
+void QQuickSpinBox::hoverEnterEvent(QHoverEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::hoverEnterEvent(event);
+ d->updateHover(event->posF());
+}
+
+void QQuickSpinBox::hoverMoveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::hoverMoveEvent(event);
+ d->updateHover(event->posF());
+}
+
+void QQuickSpinBox::hoverLeaveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickSpinBox);
+ QQuickControl::hoverLeaveEvent(event);
+ d->down->setHovered(false);
+ d->up->setHovered(false);
+}
+
void QQuickSpinBox::keyPressEvent(QKeyEvent *event)
{
Q_D(QQuickSpinBox);
@@ -730,8 +766,9 @@ QAccessible::Role QQuickSpinBox::accessibleRole() const
class QQuickSpinButtonPrivate : public QObjectPrivate
{
public:
- QQuickSpinButtonPrivate() : pressed(false), indicator(nullptr) { }
+ QQuickSpinButtonPrivate() : pressed(false), hovered(false), indicator(nullptr) { }
bool pressed;
+ bool hovered;
QQuickItem *indicator;
};
@@ -756,6 +793,22 @@ void QQuickSpinButton::setPressed(bool pressed)
emit pressedChanged();
}
+bool QQuickSpinButton::isHovered() const
+{
+ Q_D(const QQuickSpinButton);
+ return d->hovered;
+}
+
+void QQuickSpinButton::setHovered(bool hovered)
+{
+ Q_D(QQuickSpinButton);
+ if (d->hovered == hovered)
+ return;
+
+ d->hovered = hovered;
+ emit hoveredChanged();
+}
+
QQuickItem *QQuickSpinButton::indicator() const
{
Q_D(const QQuickSpinButton);
diff --git a/src/quicktemplates2/qquickspinbox_p.h b/src/quicktemplates2/qquickspinbox_p.h
index 3898a28b..b34f81a2 100644
--- a/src/quicktemplates2/qquickspinbox_p.h
+++ b/src/quicktemplates2/qquickspinbox_p.h
@@ -118,6 +118,9 @@ Q_SIGNALS:
protected:
bool childMouseEventFilter(QQuickItem *child, QEvent *event) override;
+ void hoverEnterEvent(QHoverEvent *event) override;
+ void hoverMoveEvent(QHoverEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
void keyReleaseEvent(QKeyEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
@@ -146,6 +149,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSpinButton : public QObject
{
Q_OBJECT
Q_PROPERTY(bool pressed READ isPressed WRITE setPressed NOTIFY pressedChanged FINAL)
+ Q_PROPERTY(bool hovered READ isHovered WRITE setHovered NOTIFY hoveredChanged FINAL REVISION 1)
Q_PROPERTY(QQuickItem *indicator READ indicator WRITE setIndicator NOTIFY indicatorChanged FINAL)
public:
@@ -154,11 +158,15 @@ public:
bool isPressed() const;
void setPressed(bool pressed);
+ bool isHovered() const;
+ void setHovered(bool hovered);
+
QQuickItem *indicator() const;
void setIndicator(QQuickItem *indicator);
Q_SIGNALS:
void pressedChanged();
+ Q_REVISION(1) void hoveredChanged();
void indicatorChanged();
private:
diff --git a/src/quicktemplates2/qquickstackview.cpp b/src/quicktemplates2/qquickstackview.cpp
index 8cb06d06..df163089 100644
--- a/src/quicktemplates2/qquickstackview.cpp
+++ b/src/quicktemplates2/qquickstackview.cpp
@@ -289,12 +289,7 @@ QQuickStackView::~QQuickStackView()
QQuickStackAttached *QQuickStackView::qmlAttachedProperties(QObject *object)
{
- QQuickItem *item = qobject_cast<QQuickItem *>(object);
- if (!item) {
- qmlInfo(object) << "StackView must be attached to an Item";
- return nullptr;
- }
- return new QQuickStackAttached(item);
+ return new QQuickStackAttached(object);
}
/*!
@@ -438,8 +433,11 @@ QQuickItem *QQuickStackView::find(const QJSValue &callback, LoadBehavior behavio
An \a operation can be optionally specified as the last argument. Supported
operations:
- \value StackView.Transition An operation with transitions.
+ \value StackView.Transition An operation with default transitions (default).
\value StackView.Immediate An immediate operation without transitions.
+ \value StackView.PushTransition An operation with push transitions (since QtQuick.Controls 2.1).
+ \value StackView.ReplaceTransition An operation with replace transitions (since QtQuick.Controls 2.1).
+ \value StackView.PopTransition An operation with pop transitions (since QtQuick.Controls 2.1).
\sa initialItem
*/
@@ -455,7 +453,7 @@ void QQuickStackView::push(QQmlV4Function *args)
QV4::ExecutionEngine *v4 = args->v4engine();
QV4::Scope scope(v4);
- Operation operation = d->elements.isEmpty() ? Immediate : Transition;
+ Operation operation = d->elements.isEmpty() ? Immediate : PushTransition;
QV4::ScopedValue lastArg(scope, (*args)[args->length() - 1]);
if (lastArg->isInt32())
operation = static_cast<Operation>(lastArg->toInt32());
@@ -474,7 +472,9 @@ void QQuickStackView::push(QQmlV4Function *args)
if (d->pushElements(elements)) {
emit depthChanged();
QQuickStackElement *enter = d->elements.top();
- d->pushTransition(enter, exit, boundingRect(), operation == Immediate);
+ d->startTransition(QQuickStackTransition::pushEnter(operation, enter, this),
+ QQuickStackTransition::pushExit(operation, exit, this),
+ operation == Immediate);
d->setCurrentItem(enter->item);
}
@@ -499,8 +499,11 @@ void QQuickStackView::push(QQmlV4Function *args)
An \a operation can be optionally specified as the last argument. Supported
operations:
- \value StackView.Transition An operation with transitions.
+ \value StackView.Transition An operation with default transitions (default).
\value StackView.Immediate An immediate operation without transitions.
+ \value StackView.PushTransition An operation with push transitions (since QtQuick.Controls 2.1).
+ \value StackView.ReplaceTransition An operation with replace transitions (since QtQuick.Controls 2.1).
+ \value StackView.PopTransition An operation with pop transitions (since QtQuick.Controls 2.1).
Examples:
\code
@@ -546,7 +549,7 @@ void QQuickStackView::pop(QQmlV4Function *args)
}
}
- Operation operation = Transition;
+ Operation operation = PopTransition;
if (argc > 0) {
QV4::ScopedValue lastArg(scope, (*args)[argc - 1]);
if (lastArg->isInt32())
@@ -556,10 +559,14 @@ void QQuickStackView::pop(QQmlV4Function *args)
QQuickItem *previousItem = nullptr;
if (d->popElements(enter)) {
- if (exit)
+ if (exit) {
+ exit->removal = true;
previousItem = exit->item;
+ }
emit depthChanged();
- d->popTransition(enter, exit, boundingRect(), operation == Immediate);
+ d->startTransition(QQuickStackTransition::popExit(operation, exit, this),
+ QQuickStackTransition::popEnter(operation, enter, this),
+ operation == Immediate);
d->setCurrentItem(enter->item);
}
@@ -622,8 +629,39 @@ void QQuickStackView::pop(QQmlV4Function *args)
An \a operation can be optionally specified as the last argument. Supported
operations:
- \value StackView.Transition An operation with transitions.
+ \value StackView.Transition An operation with default transitions (default).
\value StackView.Immediate An immediate operation without transitions.
+ \value StackView.PushTransition An operation with push transitions (since QtQuick.Controls 2.1).
+ \value StackView.ReplaceTransition An operation with replace transitions (since QtQuick.Controls 2.1).
+ \value StackView.PopTransition An operation with pop transitions (since QtQuick.Controls 2.1).
+
+ The following example illustrates the use of push and pop transitions with replace().
+
+ \code
+ StackView {
+ id: stackView
+
+ initialItem: Component {
+ id: page
+
+ Page {
+ Row {
+ spacing: 20
+ anchors.centerIn: parent
+
+ Button {
+ text: "<"
+ onClicked: stackView.replace(page, StackView.PopTransition)
+ }
+ Button {
+ text: ">"
+ onClicked: stackView.replace(page, StackView.PushTransition)
+ }
+ }
+ }
+ }
+ }
+ \endcode
\sa push()
*/
@@ -639,7 +677,7 @@ void QQuickStackView::replace(QQmlV4Function *args)
QV4::ExecutionEngine *v4 = args->v4engine();
QV4::Scope scope(v4);
- Operation operation = d->elements.isEmpty() ? Immediate : Transition;
+ Operation operation = d->elements.isEmpty() ? Immediate : ReplaceTransition;
QV4::ScopedValue lastArg(scope, (*args)[args->length() - 1]);
if (lastArg->isInt32())
operation = static_cast<Operation>(lastArg->toInt32());
@@ -666,8 +704,12 @@ void QQuickStackView::replace(QQmlV4Function *args)
if (exit != target ? d->replaceElements(target, elements) : d->pushElements(elements)) {
if (depth != d->elements.count())
emit depthChanged();
+ if (exit)
+ exit->removal = true;
QQuickStackElement *enter = d->elements.top();
- d->replaceTransition(enter, exit, boundingRect(), operation == Immediate);
+ d->startTransition(QQuickStackTransition::replaceExit(operation, exit, this),
+ QQuickStackTransition::replaceEnter(operation, enter, this),
+ operation == Immediate);
d->setCurrentItem(enter->item);
}
@@ -946,19 +988,25 @@ void QQuickStackAttachedPrivate::itemParentChanged(QQuickItem *item, QQuickItem
emit q->statusChanged();
}
-QQuickStackAttached::QQuickStackAttached(QQuickItem *parent) :
+QQuickStackAttached::QQuickStackAttached(QObject *parent) :
QObject(*(new QQuickStackAttachedPrivate), parent)
{
Q_D(QQuickStackAttached);
- QQuickItemPrivate::get(parent)->addItemChangeListener(d, QQuickItemPrivate::Parent);
- d->itemParentChanged(parent, parent->parentItem());
+ QQuickItem *item = qobject_cast<QQuickItem *>(parent);
+ if (item) {
+ QQuickItemPrivate::get(item)->addItemChangeListener(d, QQuickItemPrivate::Parent);
+ d->itemParentChanged(item, item->parentItem());
+ } else if (parent) {
+ qmlInfo(parent) << "StackView must be attached to an Item";
+ }
}
QQuickStackAttached::~QQuickStackAttached()
{
Q_D(QQuickStackAttached);
- QQuickItem *parentItem = static_cast<QQuickItem *>(parent());
- QQuickItemPrivate::get(parentItem)->removeItemChangeListener(d, QQuickItemPrivate::Parent);
+ QQuickItem *parentItem = qobject_cast<QQuickItem *>(parent());
+ if (parentItem)
+ QQuickItemPrivate::get(parentItem)->removeItemChangeListener(d, QQuickItemPrivate::Parent);
}
/*!
@@ -1006,4 +1054,42 @@ QQuickStackView::Status QQuickStackAttached::status() const
return d->element ? d->element->status : QQuickStackView::Inactive;
}
+/*!
+ \qmlattachedsignal QtQuick.Controls::StackView::activated()
+ \since QtQuick.Controls 2.1
+
+ This attached signal is emitted when the item it's attached to is activated in the stack.
+
+ \sa status
+*/
+
+/*!
+ \qmlattachedsignal QtQuick.Controls::StackView::deactivated()
+ \since QtQuick.Controls 2.1
+
+ This attached signal is emitted when the item it's attached to is deactivated in the stack.
+
+ \sa status
+*/
+
+/*!
+ \qmlattachedsignal QtQuick.Controls::StackView::activating()
+ \since QtQuick.Controls 2.1
+
+ This attached signal is emitted when the item it's attached to is in the process of being
+ activated in the stack.
+
+ \sa status
+*/
+
+/*!
+ \qmlattachedsignal QtQuick.Controls::StackView::deactivating()
+ \since QtQuick.Controls 2.1
+
+ This attached signal is emitted when the item it's attached to is in the process of being
+ dectivated in the stack.
+
+ \sa status
+*/
+
QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickstackview_p.cpp b/src/quicktemplates2/qquickstackview_p.cpp
index c1b68652..0f5674c2 100644
--- a/src/quicktemplates2/qquickstackview_p.cpp
+++ b/src/quicktemplates2/qquickstackview_p.cpp
@@ -72,7 +72,7 @@ private:
QQuickStackElement::QQuickStackElement() : QQuickItemViewTransitionableItem(nullptr),
index(-1), init(false), removal(false), ownItem(false), ownComponent(false), widthValid(false), heightValid(false),
- context(nullptr), component(nullptr), incubator(nullptr), view(nullptr),
+ context(nullptr), component(nullptr), view(nullptr),
status(QQuickStackView::Inactive)
{
}
@@ -107,7 +107,6 @@ QQuickStackElement::~QQuickStackElement()
}
delete context;
- delete incubator;
}
QQuickStackElement *QQuickStackElement::fromString(const QString &str, QQuickStackView *view)
@@ -120,12 +119,9 @@ QQuickStackElement *QQuickStackElement::fromString(const QString &str, QQuickSta
QQuickStackElement *QQuickStackElement::fromObject(QObject *object, QQuickStackView *view)
{
+ Q_UNUSED(view);
QQuickStackElement *element = new QQuickStackElement;
element->component = qobject_cast<QQmlComponent *>(object);
- if (!element->component) {
- element->component = new QQmlComponent(qmlEngine(view), view);
- element->ownComponent = true;
- }
element->item = qobject_cast<QQuickItem *>(object);
if (element->item)
element->originalParent = element->item->parentItem();
@@ -144,9 +140,8 @@ bool QQuickStackElement::load(QQuickStackView *parent)
context = new QQmlContext(creationContext);
context->setContextObject(parent);
- delete incubator;
- incubator = new QQuickStackIncubator(this);
- component->create(*incubator, context);
+ QQuickStackIncubator incubator(this);
+ component->create(incubator, context);
if (component->isError())
qWarning() << qPrintable(component->errorString().trimmed());
} else {
@@ -179,14 +174,15 @@ void QQuickStackElement::initialize()
p->addItemChangeListener(this, QQuickItemPrivate::Destroyed);
if (!properties.isUndefined()) {
- QQmlComponentPrivate *d = QQmlComponentPrivate::get(component);
- Q_ASSERT(d && d->engine);
- QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(d->engine);
+ QQmlEngine *engine = qmlEngine(view);
+ Q_ASSERT(engine);
+ QV4::ExecutionEngine *v4 = QQmlEnginePrivate::getV4Engine(engine);
Q_ASSERT(v4);
QV4::Scope scope(v4);
QV4::ScopedValue ipv(scope, properties.value());
QV4::Scoped<QV4::QmlContext> qmlContext(scope, qmlCallingContext.value());
- d->initializeObjectWithInitialProperties(qmlContext, ipv, item);
+ QV4::ScopedValue qmlObject(scope, QV4::QObjectWrapper::wrap(v4, item));
+ QQmlComponentPrivate::setInitialProperties(v4, qmlContext, qmlObject, ipv);
properties.clear();
}
@@ -222,8 +218,28 @@ void QQuickStackElement::setStatus(QQuickStackView::Status value)
status = value;
QQuickStackAttached *attached = attachedStackObject(this);
- if (attached)
- emit attached->statusChanged();
+ if (!attached)
+ return;
+
+ switch (value) {
+ case QQuickStackView::Inactive:
+ emit attached->deactivated();
+ break;
+ case QQuickStackView::Deactivating:
+ emit attached->deactivating();
+ break;
+ case QQuickStackView::Activating:
+ emit attached->activating();
+ break;
+ case QQuickStackView::Active:
+ emit attached->activated();
+ break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+
+ emit attached->statusChanged();
}
void QQuickStackElement::transitionNextReposition(QQuickItemViewTransitioner *transitioner, QQuickItemViewTransitioner::TransitionType type, bool asTarget)
@@ -411,96 +427,28 @@ void QQuickStackViewPrivate::ensureTransitioner()
}
}
-void QQuickStackViewPrivate::popTransition(QQuickStackElement *enter, QQuickStackElement *exit, const QRectF &viewBounds, bool immediate)
-{
- ensureTransitioner();
-
- if (exit) {
- exit->removal = true;
- exit->setStatus(QQuickStackView::Deactivating);
- exit->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, true);
- }
- if (enter) {
- enter->setStatus(QQuickStackView::Activating);
- enter->transitionNextReposition(transitioner, QQuickItemViewTransitioner::RemoveTransition, false);
- }
-
- if (exit) {
- if (immediate || !exit->item || !exit->prepareTransition(transitioner, viewBounds))
- completeTransition(exit, transitioner->removeTransition);
- else
- exit->startTransition(transitioner);
- }
- if (enter) {
- if (immediate || !enter->item || !enter->prepareTransition(transitioner, QRectF()))
- completeTransition(enter, transitioner->removeDisplacedTransition);
- else
- enter->startTransition(transitioner);
- }
-
- if (transitioner) {
- setBusy(!transitioner->runningJobs.isEmpty());
- transitioner->resetTargetLists();
- }
-}
-
-void QQuickStackViewPrivate::pushTransition(QQuickStackElement *enter, QQuickStackElement *exit, const QRectF &viewBounds, bool immediate)
-{
- ensureTransitioner();
-
- if (enter) {
- enter->setStatus(QQuickStackView::Activating);
- enter->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, true);
- }
- if (exit) {
- exit->setStatus(QQuickStackView::Deactivating);
- exit->transitionNextReposition(transitioner, QQuickItemViewTransitioner::AddTransition, false);
- }
-
- if (enter) {
- if (immediate || !enter->item || !enter->prepareTransition(transitioner, viewBounds))
- completeTransition(enter, transitioner->addTransition);
- else
- enter->startTransition(transitioner);
- }
- if (exit) {
- if (immediate || !exit->item || !exit->prepareTransition(transitioner, QRectF()))
- completeTransition(exit, transitioner->addDisplacedTransition);
- else
- exit->startTransition(transitioner);
- }
-
- if (transitioner) {
- setBusy(!transitioner->runningJobs.isEmpty());
- transitioner->resetTargetLists();
- }
-}
-
-void QQuickStackViewPrivate::replaceTransition(QQuickStackElement *enter, QQuickStackElement *exit, const QRectF &viewBounds, bool immediate)
+void QQuickStackViewPrivate::startTransition(const QQuickStackTransition &first, const QQuickStackTransition &second, bool immediate)
{
- ensureTransitioner();
-
- if (exit) {
- exit->removal = true;
- exit->setStatus(QQuickStackView::Deactivating);
- exit->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, false);
+ if (first.element) {
+ first.element->setStatus(first.status);
+ first.element->transitionNextReposition(transitioner, first.type, first.target);
}
- if (enter) {
- enter->setStatus(QQuickStackView::Activating);
- enter->transitionNextReposition(transitioner, QQuickItemViewTransitioner::MoveTransition, true);
+ if (second.element) {
+ second.element->setStatus(second.status);
+ second.element->transitionNextReposition(transitioner, second.type, second.target);
}
- if (exit) {
- if (immediate || !exit->item || !exit->prepareTransition(transitioner, QRectF()))
- completeTransition(exit, transitioner->moveDisplacedTransition);
+ if (first.element) {
+ if (immediate || !first.element->item || !first.element->prepareTransition(transitioner, first.viewBounds))
+ completeTransition(first.element, transitioner->removeTransition);
else
- exit->startTransition(transitioner);
+ first.element->startTransition(transitioner);
}
- if (enter) {
- if (immediate || !enter->item || !enter->prepareTransition(transitioner, viewBounds))
- completeTransition(enter, transitioner->moveTransition);
+ if (second.element) {
+ if (immediate || !second.element->item || !second.element->prepareTransition(transitioner, second.viewBounds))
+ completeTransition(second.element, transitioner->removeDisplacedTransition);
else
- enter->startTransition(transitioner);
+ second.element->startTransition(transitioner);
}
if (transitioner) {
@@ -554,4 +502,119 @@ void QQuickStackViewPrivate::setBusy(bool b)
emit q->busyChanged();
}
+static QQuickStackTransition exitTransition(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ QQuickStackTransition st;
+ st.status = QQuickStackView::Deactivating;
+ st.transition = nullptr;
+ st.element = element;
+
+ const QQuickItemViewTransitioner *transitioner = QQuickStackViewPrivate::get(view)->transitioner;
+
+ switch (operation) {
+ case QQuickStackView::PushTransition:
+ st.target = false;
+ st.type = QQuickItemViewTransitioner::AddTransition;
+ st.viewBounds = QRectF();
+ if (transitioner)
+ st.transition = transitioner->addDisplacedTransition;
+ break;
+ case QQuickStackView::ReplaceTransition:
+ st.target = false;
+ st.type = QQuickItemViewTransitioner::MoveTransition;
+ st.viewBounds = QRectF();
+ if (transitioner)
+ st.transition = transitioner->moveDisplacedTransition;
+ break;
+ case QQuickStackView::PopTransition:
+ st.target = true;
+ st.type = QQuickItemViewTransitioner::RemoveTransition;
+ st.viewBounds = view->boundingRect();
+ if (transitioner)
+ st.transition = transitioner->removeTransition;
+ break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+
+ return st;
+}
+
+static QQuickStackTransition enterTransition(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ QQuickStackTransition st;
+ st.status = QQuickStackView::Activating;
+ st.transition = nullptr;
+ st.element = element;
+
+ const QQuickItemViewTransitioner *transitioner = QQuickStackViewPrivate::get(view)->transitioner;
+
+ switch (operation) {
+ case QQuickStackView::PushTransition:
+ st.target = true;
+ st.type = QQuickItemViewTransitioner::AddTransition;
+ st.viewBounds = view->boundingRect();
+ if (transitioner)
+ st.transition = transitioner->addTransition;
+ break;
+ case QQuickStackView::ReplaceTransition:
+ st.target = true;
+ st.type = QQuickItemViewTransitioner::MoveTransition;
+ st.viewBounds = view->boundingRect();
+ if (transitioner)
+ st.transition = transitioner->moveTransition;
+ break;
+ case QQuickStackView::PopTransition:
+ st.target = false;
+ st.type = QQuickItemViewTransitioner::RemoveTransition;
+ st.viewBounds = QRectF();
+ if (transitioner)
+ st.transition = transitioner->removeDisplacedTransition;
+ break;
+ default:
+ Q_UNREACHABLE();
+ break;
+ }
+
+ return st;
+}
+
+static QQuickStackView::Operation operationTransition(QQuickStackView::Operation operation, QQuickStackView::Operation transition)
+{
+ if (operation == QQuickStackView::Immediate || operation == QQuickStackView::Transition)
+ return transition;
+ return operation;
+}
+
+QQuickStackTransition QQuickStackTransition::popExit(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ return exitTransition(operationTransition(operation, QQuickStackView::PopTransition), element, view);
+}
+
+QQuickStackTransition QQuickStackTransition::popEnter(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ return enterTransition(operationTransition(operation, QQuickStackView::PopTransition), element, view);
+}
+
+QQuickStackTransition QQuickStackTransition::pushExit(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ return exitTransition(operationTransition(operation, QQuickStackView::PushTransition), element, view);
+}
+
+QQuickStackTransition QQuickStackTransition::pushEnter(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ return enterTransition(operationTransition(operation, QQuickStackView::PushTransition), element, view);
+}
+
+QQuickStackTransition QQuickStackTransition::replaceExit(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ return exitTransition(operationTransition(operation, QQuickStackView::ReplaceTransition), element, view);
+}
+
+QQuickStackTransition QQuickStackTransition::replaceEnter(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view)
+{
+ return enterTransition(operationTransition(operation, QQuickStackView::ReplaceTransition), element, view);
+}
+
QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickstackview_p.h b/src/quicktemplates2/qquickstackview_p.h
index 5c119627..d8b6ce7c 100644
--- a/src/quicktemplates2/qquickstackview_p.h
+++ b/src/quicktemplates2/qquickstackview_p.h
@@ -121,8 +121,11 @@ public:
Q_INVOKABLE QQuickItem *find(const QJSValue &callback, LoadBehavior behavior = DontLoad);
enum Operation {
- Transition,
- Immediate
+ Transition = -1, // deprecated
+ Immediate = 0,
+ PushTransition = 1,
+ ReplaceTransition = 2,
+ PopTransition = 3,
};
Q_ENUM(Operation)
@@ -164,7 +167,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickStackAttached : public QObject
Q_PROPERTY(QQuickStackView::Status status READ status NOTIFY statusChanged FINAL)
public:
- explicit QQuickStackAttached(QQuickItem *parent = nullptr);
+ explicit QQuickStackAttached(QObject *parent = nullptr);
~QQuickStackAttached();
int index() const;
@@ -175,6 +178,10 @@ Q_SIGNALS:
void indexChanged();
void viewChanged();
void statusChanged();
+ /*Q_REVISION(1)*/ void activated();
+ /*Q_REVISION(1)*/ void activating();
+ /*Q_REVISION(1)*/ void deactivated();
+ /*Q_REVISION(1)*/ void deactivating();
private:
Q_DISABLE_COPY(QQuickStackAttached)
diff --git a/src/quicktemplates2/qquickstackview_p_p.h b/src/quicktemplates2/qquickstackview_p_p.h
index 679cee09..c7691c40 100644
--- a/src/quicktemplates2/qquickstackview_p_p.h
+++ b/src/quicktemplates2/qquickstackview_p_p.h
@@ -58,7 +58,7 @@ QT_BEGIN_NAMESPACE
class QQmlContext;
class QQmlComponent;
-class QQmlIncubator;
+struct QQuickStackTransition;
class QQuickStackElement : public QQuickItemViewTransitionableItem, public QQuickItemChangeListener
{
@@ -93,7 +93,6 @@ public:
bool heightValid;
QQmlContext *context;
QQmlComponent *component;
- QQmlIncubator *incubator;
QQuickStackView *view;
QPointer<QQuickItem> originalParent;
QQuickStackView::Status status;
@@ -125,9 +124,7 @@ public:
bool replaceElements(QQuickStackElement *element, const QList<QQuickStackElement *> &elements);
void ensureTransitioner();
- void popTransition(QQuickStackElement *enter, QQuickStackElement *exit, const QRectF &viewBounds, bool immediate);
- void pushTransition(QQuickStackElement *enter, QQuickStackElement *exit, const QRectF &viewBounds, bool immediate);
- void replaceTransition(QQuickStackElement *enter, QQuickStackElement *exit, const QRectF &viewBounds, bool immediate);
+ void startTransition(const QQuickStackTransition &first, const QQuickStackTransition &second, bool immediate);
void completeTransition(QQuickStackElement *element, QQuickTransition *transition);
void viewItemTransitionFinished(QQuickItemViewTransitionableItem *item) override;
@@ -141,6 +138,25 @@ public:
QQuickItemViewTransitioner *transitioner;
};
+struct QQuickStackTransition
+{
+ static QQuickStackTransition popExit(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view);
+ static QQuickStackTransition popEnter(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view);
+
+ static QQuickStackTransition pushExit(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view);
+ static QQuickStackTransition pushEnter(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view);
+
+ static QQuickStackTransition replaceExit(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view);
+ static QQuickStackTransition replaceEnter(QQuickStackView::Operation operation, QQuickStackElement *element, QQuickStackView *view);
+
+ bool target;
+ QQuickStackView::Status status;
+ QQuickItemViewTransitioner::TransitionType type;
+ QRectF viewBounds;
+ QQuickStackElement *element;
+ QQuickTransition *transition;
+};
+
class QQuickStackAttachedPrivate : public QObjectPrivate, public QQuickItemChangeListener
{
Q_DECLARE_PUBLIC(QQuickStackAttached)
diff --git a/src/quicktemplates2/qquickswipedelegate.cpp b/src/quicktemplates2/qquickswipedelegate.cpp
index ae7a7d90..50eb7584 100644
--- a/src/quicktemplates2/qquickswipedelegate.cpp
+++ b/src/quicktemplates2/qquickswipedelegate.cpp
@@ -90,10 +90,21 @@ QT_BEGIN_NAMESPACE
\image qtquickcontrols2-swipedelegate-behind.gif
+ The following snippet shows SwipeDelegate used in a \l ListView to remove
+ items from the list:
+
+ \snippet qtquickcontrols2-swipedelegate.qml file
+
\sa {Customizing SwipeDelegate}, {Delegate Controls}
*/
namespace {
+ typedef QQuickSwipeDelegateAttached Attached;
+
+ Attached *attachedObject(QQuickItem *item) {
+ return qobject_cast<Attached*>(qmlAttachedPropertiesObject<QQuickSwipeDelegate>(item, false));
+ }
+
enum PositionAnimation {
DontAnimatePosition,
AnimatePosition
@@ -544,6 +555,14 @@ void QQuickSwipe::setComplete(bool complete)
d->complete = complete;
emit completeChanged();
+ if (d->complete)
+ emit completed();
+}
+
+void QQuickSwipe::close()
+{
+ setPosition(0);
+ setComplete(false);
}
class QQuickSwipeDelegatePrivate : public QQuickItemDelegatePrivate
@@ -577,9 +596,22 @@ bool QQuickSwipeDelegatePrivate::handleMousePressEvent(QQuickItem *item, QMouseE
return true;
}
+ // The position is non-zero, this press could be either for a delegate or the control itself
+ // (the control can be clicked to e.g. close the swipe). Either way, we must begin measuring
+ // mouse movement in case it turns into a swipe, in which case we grab the mouse.
swipePrivate->positionBeforePress = swipePrivate->position;
swipePrivate->velocityCalculator.startMeasuring(event->pos(), event->timestamp());
pressPoint = item->mapToItem(q, event->pos());
+
+ // When a delegate uses the attached properties and signals, it declares that it wants mouse events.
+ Attached *attached = attachedObject(item);
+ if (attached) {
+ attached->setPressed(true);
+ // Stop the event from propagating, as QQuickItem explicitly ignores events.
+ event->accept();
+ return true;
+ }
+
return false;
}
@@ -605,7 +637,8 @@ bool QQuickSwipeDelegatePrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEv
if (item == q && !pressed)
return false;
- const qreal distance = (event->pos() - pressPoint).x();
+ const QPointF mappedEventPos = item->mapToItem(q, event->pos());
+ const qreal distance = (mappedEventPos - pressPoint).x();
if (!q->keepMouseGrab()) {
// Taken from QQuickDrawer::handleMouseMoveEvent; see comments there.
int threshold = qMax(20, QGuiApplication::styleHints()->startDragDistance() + 5);
@@ -614,9 +647,12 @@ bool QQuickSwipeDelegatePrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEv
QQuickItem *grabber = q->window()->mouseGrabberItem();
if (!grabber || !grabber->keepMouseGrab()) {
q->grabMouse();
- q->setKeepMouseGrab(overThreshold);
+ q->setKeepMouseGrab(true);
q->setPressed(true);
swipe.setComplete(false);
+
+ if (Attached *attached = attachedObject(item))
+ attached->setPressed(false);
}
}
}
@@ -676,7 +712,7 @@ bool QQuickSwipeDelegatePrivate::handleMouseMoveEvent(QQuickItem *item, QMouseEv
static const qreal exposeVelocityThreshold = 300.0;
-bool QQuickSwipeDelegatePrivate::handleMouseReleaseEvent(QQuickItem *, QMouseEvent *event)
+bool QQuickSwipeDelegatePrivate::handleMouseReleaseEvent(QQuickItem *item, QMouseEvent *event)
{
Q_Q(QQuickSwipeDelegate);
QQuickSwipePrivate *swipePrivate = QQuickSwipePrivate::get(&swipe);
@@ -703,6 +739,14 @@ bool QQuickSwipeDelegatePrivate::handleMouseReleaseEvent(QQuickItem *, QMouseEve
swipePrivate->wasComplete = false;
}
+ if (Attached *attached = attachedObject(item)) {
+ const bool wasPressed = attached->isPressed();
+ if (wasPressed) {
+ attached->setPressed(false);
+ emit attached->clicked();
+ }
+ }
+
// Only consume child events if we had grabbed the mouse.
return hadGrabbedMouse;
}
@@ -746,6 +790,17 @@ QQuickSwipeDelegate::QQuickSwipeDelegate(QQuickItem *parent) :
}
/*!
+ \since QtQuick.Controls 2.1
+ \qmlmethod void QtQuick.Controls::SwipeDelegate::swipe.close()
+
+ This method sets the \c position of the swipe to \c 0. Any animations
+ defined for the \l {Item::}{x} position of \l {Control::}{contentItem}
+ and \l {Control::}{background} will be triggered.
+
+ \sa swipe
+*/
+
+/*!
\qmlpropertygroup QtQuick.Controls::SwipeDelegate::swipe
\qmlproperty real QtQuick.Controls::SwipeDelegate::swipe.position
\qmlproperty bool QtQuick.Controls::SwipeDelegate::swipe.complete
@@ -758,7 +813,7 @@ QQuickSwipeDelegate::QQuickSwipeDelegate(QQuickItem *parent) :
\table
\header
- \li Property
+ \li Name
\li Description
\row
\li position
@@ -820,9 +875,18 @@ QQuickSwipeDelegate::QQuickSwipeDelegate(QQuickItem *parent) :
If \c right has not been set, or the position hasn't changed since
creation of the SwipeDelegate, this property will be \c null.
+ \row
+ \li completed()
+ \li This signal is emitted when \c complete becomes \c true.
+
+ It is useful for performing some action upon completion of a swipe.
+ For example, it can be used to remove the delegate from the list
+ that it is in.
+
+ This signal was added in QtQuick.Controls 2.1.
\endtable
- \sa {Control::}{contentItem}, {Control::}{background}
+ \sa {Control::}{contentItem}, {Control::}{background}, swipe.close()
*/
QQuickSwipe *QQuickSwipeDelegate::swipe() const
{
@@ -830,6 +894,11 @@ QQuickSwipe *QQuickSwipeDelegate::swipe() const
return const_cast<QQuickSwipe*>(&d->swipe);
}
+QQuickSwipeDelegateAttached *QQuickSwipeDelegate::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickSwipeDelegateAttached(object);
+}
+
static bool isChildOrGrandchildOf(QQuickItem *child, QQuickItem *item)
{
return item && (child == item || item->isAncestorOf(child));
@@ -860,6 +929,14 @@ bool QQuickSwipeDelegate::childMouseEventFilter(QQuickItem *child, QEvent *event
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
QQuickItemDelegate::mouseReleaseEvent(mouseEvent);
return d->handleMouseReleaseEvent(child, mouseEvent);
+ } case QEvent::UngrabMouse: {
+ // If the mouse was pressed over e.g. rightItem and then dragged down,
+ // the ListView would eventually grab the mouse, at which point we must
+ // clear the pressed flag so that it doesn't stay pressed after the release.
+ Attached *attached = attachedObject(child);
+ if (attached)
+ attached->setPressed(false);
+ return false;
} default:
return false;
}
@@ -912,4 +989,155 @@ QAccessible::Role QQuickSwipeDelegate::accessibleRole() const
}
#endif
+class QQuickSwipeDelegateAttachedPrivate : public QObjectPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickSwipeDelegateAttached)
+
+public:
+ QQuickSwipeDelegateAttachedPrivate() :
+ pressed(false)
+ {
+ }
+
+ // True when left/right/behind is non-interactive and is pressed.
+ bool pressed;
+};
+
+/*!
+ \since QtQuick.Controls 2.1
+ \qmlattachedsignal QtQuick.Controls::SwipeDelegate::clicked()
+
+ This signal can be attached to a non-interactive item declared in
+ \c swipe.left, \c swipe.right, or \c swipe.behind, in order to react to
+ clicks. Items can only be clicked when \c swipe.complete is \c true.
+
+ For interactive controls (such as \l Button) declared in these
+ items, use their respective \c clicked() signal instead.
+
+ To respond to clicks on the SwipeDelegate itself, use its
+ \l {AbstractButton::}{clicked()} signal.
+
+ \note See the documentation for \l pressed for information on
+ how to use the event-related properties correctly.
+
+ \sa pressed
+*/
+
+QQuickSwipeDelegateAttached::QQuickSwipeDelegateAttached(QObject *object) :
+ QObject(*(new QQuickSwipeDelegateAttachedPrivate), object)
+{
+ QQuickItem *item = qobject_cast<QQuickItem *>(object);
+ if (item) {
+ // This allows us to be notified when an otherwise non-interactive item
+ // is pressed and clicked. The alternative is much more more complex:
+ // iterating through children that contain the event pos and finding
+ // the first one with an attached object.
+ item->setAcceptedMouseButtons(Qt::AllButtons);
+ } else {
+ qWarning() << "Attached properties of SwipeDelegate must be accessed through an Item";
+ }
+}
+
+/*!
+ \since QtQuick.Controls 2.1
+ \qmlattachedproperty bool QtQuick.Controls::SwipeDelegate::pressed
+ \readonly
+
+ This property can be attached to a non-interactive item declared in
+ \c swipe.left, \c swipe.right, or \c swipe.behind, in order to detect if it
+ is pressed. Items can only be pressed when \c swipe.complete is \c true.
+
+ For example:
+
+ \code
+ swipe.right: Label {
+ anchors.right: parent.right
+ height: parent.height
+ text: "Action"
+ color: "white"
+ padding: 12
+ background: Rectangle {
+ color: SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato"
+ }
+ }
+ \endcode
+
+ It is possible to have multiple items which individually receive mouse and
+ touch events. For example, to have two actions in the \c swipe.right item,
+ use the following code:
+
+ \code
+ swipe.right: Row {
+ anchors.right: parent.right
+ height: parent.height
+
+ Label {
+ id: moveLabel
+ text: qsTr("Move")
+ color: "white"
+ verticalAlignment: Label.AlignVCenter
+ padding: 12
+ height: parent.height
+
+ SwipeDelegate.onClicked: console.log("Moving...")
+
+ background: Rectangle {
+ color: moveLabel.SwipeDelegate.pressed ? Qt.darker("#ffbf47", 1.1) : "#ffbf47"
+ }
+ }
+ Label {
+ id: deleteLabel
+ text: qsTr("Delete")
+ color: "white"
+ verticalAlignment: Label.AlignVCenter
+ padding: 12
+ height: parent.height
+
+ SwipeDelegate.onClicked: console.log("Deleting...")
+
+ background: Rectangle {
+ color: deleteLabel.SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato"
+ }
+ }
+ }
+ \endcode
+
+ Note how the \c color assignment in each \l {Control::}{background} item
+ qualifies the attached property with the \c id of the label. This
+ is important; using the attached properties on an item causes that item
+ to accept events. Suppose we had left out the \c id in the previous example:
+
+ \code
+ color: SwipeDelegate.pressed ? Qt.darker("tomato", 1.1) : "tomato"
+ \endcode
+
+ The \l Rectangle background item is a child of the label, so it naturally
+ receives events before it. In practice, this means that the background
+ color will change, but the \c onClicked handler in the label will never
+ get called.
+
+ For interactive controls (such as \l Button) declared in these
+ items, use their respective \c pressed property instead.
+
+ For presses on the SwipeDelegate itself, use its
+ \l {AbstractButton::}{pressed} property.
+
+ \sa clicked()
+*/
+bool QQuickSwipeDelegateAttached::isPressed() const
+{
+ Q_D(const QQuickSwipeDelegateAttached);
+ return d->pressed;
+}
+
+void QQuickSwipeDelegateAttached::setPressed(bool pressed)
+{
+ Q_D(QQuickSwipeDelegateAttached);
+ if (pressed == d->pressed)
+ return;
+
+ d->pressed = pressed;
+ emit pressedChanged();
+}
+
QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickswipedelegate_p.h b/src/quicktemplates2/qquickswipedelegate_p.h
index e71455b0..49f6c939 100644
--- a/src/quicktemplates2/qquickswipedelegate_p.h
+++ b/src/quicktemplates2/qquickswipedelegate_p.h
@@ -54,6 +54,8 @@ QT_BEGIN_NAMESPACE
class QQuickSwipeDelegatePrivate;
class QQuickSwipe;
+class QQuickSwipeDelegateAttached;
+class QQuickSwipeDelegateAttachedPrivate;
class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipeDelegate : public QQuickItemDelegate
{
@@ -65,6 +67,8 @@ public:
QQuickSwipe *swipe() const;
+ static QQuickSwipeDelegateAttached *qmlAttachedProperties(QObject *object);
+
protected:
bool childMouseEventFilter(QQuickItem *child, QEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
@@ -125,9 +129,12 @@ public:
QQuickItem *rightItem() const;
void setRightItem(QQuickItem *item);
+ Q_REVISION(1) Q_INVOKABLE void close();
+
Q_SIGNALS:
void positionChanged();
void completeChanged();
+ Q_REVISION(1) void completed();
void leftChanged();
void behindChanged();
void rightChanged();
@@ -140,8 +147,29 @@ private:
Q_DECLARE_PRIVATE(QQuickSwipe)
};
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipeDelegateAttached : public QObject
+{
+ Q_OBJECT
+ Q_PROPERTY(bool pressed READ isPressed NOTIFY pressedChanged FINAL)
+
+public:
+ explicit QQuickSwipeDelegateAttached(QObject *object = nullptr);
+
+ bool isPressed() const;
+ void setPressed(bool pressed);
+
+Q_SIGNALS:
+ void pressedChanged();
+ void clicked();
+
+private:
+ Q_DISABLE_COPY(QQuickSwipeDelegateAttached)
+ Q_DECLARE_PRIVATE(QQuickSwipeDelegateAttached)
+};
+
QT_END_NAMESPACE
QML_DECLARE_TYPE(QQuickSwipeDelegate)
+QML_DECLARE_TYPEINFO(QQuickSwipeDelegate, QML_HAS_ATTACHED_PROPERTIES)
#endif // QQUICKSWIPEDELEGATE_P_H
diff --git a/src/quicktemplates2/qquickswipeview.cpp b/src/quicktemplates2/qquickswipeview.cpp
index e5c98f4d..a3f52edd 100644
--- a/src/quicktemplates2/qquickswipeview.cpp
+++ b/src/quicktemplates2/qquickswipeview.cpp
@@ -69,6 +69,29 @@ QT_BEGIN_NAMESPACE
\l {Container::moveItem()}{move}, and \l {Container::removeItem()}{remove}
pages dynamically at run time.
+ It is generally not advisable to add excessive amounts of pages to a
+ SwipeView. However, when the amount of pages grows larger, or individual
+ pages are relatively complex, it may be desired free up resources by
+ unloading pages that are outside the reach. The following example presents
+ how to use \l Loader to keep a maximum of three pages simultaneously
+ instantiated.
+
+ \code
+ SwipeView {
+ Repeater {
+ model: 6
+ Loader {
+ active: SwipeView.isCurrentItem || SwipeView.isNextItem || SwipeView.isPreviousItem
+ sourceComponent: Text {
+ text: index
+ Component.onCompleted: console.log("created:", index)
+ Component.onDestruction: console.log("destroyed:", index)
+ }
+ }
+ }
+ }
+ \endcode
+
\note SwipeView takes over the geometry management of items added to the
view. Using anchors on the items is not supported, and any \c width
or \c height assignment will be overridden by the view. Notice that
@@ -83,10 +106,14 @@ class QQuickSwipeViewPrivate : public QQuickContainerPrivate
Q_DECLARE_PUBLIC(QQuickSwipeView)
public:
+ QQuickSwipeViewPrivate() : interactive(true) { }
+
void resizeItem(QQuickItem *item);
void resizeItems();
static QQuickSwipeViewPrivate *get(QQuickSwipeView *view);
+
+ bool interactive;
};
void QQuickSwipeViewPrivate::resizeItems()
@@ -120,15 +147,34 @@ QQuickSwipeView::QQuickSwipeView(QQuickItem *parent) :
setActiveFocusOnTab(true);
}
-QQuickSwipeViewAttached *QQuickSwipeView::qmlAttachedProperties(QObject *object)
+/*!
+ \since QtQuick.Controls 2.1
+ \qmlproperty bool QtQuick.Controls::SwipeView::interactive
+
+ This property describes whether the user can interact with the SwipeView.
+ The user cannot swipe a view that is not interactive.
+
+ The default value is \c true.
+*/
+bool QQuickSwipeView::isInteractive() const
{
- QQuickItem *item = qobject_cast<QQuickItem *>(object);
- if (!item) {
- qWarning() << "SwipeView: attached properties must be accessed from within a child item";
- return nullptr;
- }
+ Q_D(const QQuickSwipeView);
+ return d->interactive;
+}
+
+void QQuickSwipeView::setInteractive(bool interactive)
+{
+ Q_D(QQuickSwipeView);
+ if (d->interactive == interactive)
+ return;
- return new QQuickSwipeViewAttached(item);
+ d->interactive = interactive;
+ emit interactiveChanged();
+}
+
+QQuickSwipeViewAttached *QQuickSwipeView::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickSwipeViewAttached(object);
}
void QQuickSwipeView::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
@@ -165,6 +211,26 @@ void QQuickSwipeView::itemAdded(int, QQuickItem *item)
*/
/*!
+ \qmlattachedproperty bool QtQuick.Controls::SwipeView::isNextItem
+ \since QtQuick.Controls 2.1
+ \readonly
+
+ This attached property is \c true if this child is the next item.
+
+ It is attached to each child item of the SwipeView.
+*/
+
+/*!
+ \qmlattachedproperty bool QtQuick.Controls::SwipeView::isPreviousItem
+ \since QtQuick.Controls 2.1
+ \readonly
+
+ This attached property is \c true if this child is the previous item.
+
+ It is attached to each child item of the SwipeView.
+*/
+
+/*!
\qmlattachedproperty SwipeView QtQuick.Controls::SwipeView::view
\readonly
@@ -177,11 +243,11 @@ class QQuickSwipeViewAttachedPrivate : public QObjectPrivate, public QQuickItemC
{
Q_DECLARE_PUBLIC(QQuickSwipeViewAttached)
public:
- QQuickSwipeViewAttachedPrivate(QQuickItem *item) :
- item(item),
+ QQuickSwipeViewAttachedPrivate() :
+ item(nullptr),
swipeView(nullptr),
index(-1),
- isCurrent(false)
+ currentIndex(-1)
{
}
@@ -196,19 +262,16 @@ public:
void itemDestroyed(QQuickItem *) override;
void updateIndex();
- void updateIsCurrent();
+ void updateCurrentIndex();
void setView(QQuickSwipeView *view);
void setIndex(int i);
- void setIsCurrent(bool current);
+ void setCurrentIndex(int i);
QQuickItem *item;
QQuickSwipeView *swipeView;
int index;
- // Better to store this so that we don't need to lump its calculation
- // together with index's calculation, as it would otherwise need to know
- // the old index to know if it should emit the change signal.
- bool isCurrent;
+ int currentIndex;
};
void QQuickSwipeViewAttachedPrivate::updateIndex()
@@ -216,9 +279,9 @@ void QQuickSwipeViewAttachedPrivate::updateIndex()
setIndex(swipeView ? QQuickSwipeViewPrivate::get(swipeView)->contentModel->indexOf(item, nullptr) : -1);
}
-void QQuickSwipeViewAttachedPrivate::updateIsCurrent()
+void QQuickSwipeViewAttachedPrivate::updateCurrentIndex()
{
- setIsCurrent(swipeView ? swipeView->currentIndex() == index : false);
+ setCurrentIndex(swipeView ? swipeView->currentIndex() : -1);
}
void QQuickSwipeViewAttachedPrivate::setView(QQuickSwipeView *view)
@@ -231,7 +294,7 @@ void QQuickSwipeViewAttachedPrivate::setView(QQuickSwipeView *view)
p->removeItemChangeListener(this, QQuickItemPrivate::Children);
disconnect(swipeView, &QQuickSwipeView::currentIndexChanged,
- this, &QQuickSwipeViewAttachedPrivate::updateIsCurrent);
+ this, &QQuickSwipeViewAttachedPrivate::updateCurrentIndex);
disconnect(swipeView, &QQuickSwipeView::contentChildrenChanged,
this, &QQuickSwipeViewAttachedPrivate::updateIndex);
}
@@ -243,7 +306,7 @@ void QQuickSwipeViewAttachedPrivate::setView(QQuickSwipeView *view)
p->addItemChangeListener(this, QQuickItemPrivate::Children);
connect(swipeView, &QQuickSwipeView::currentIndexChanged,
- this, &QQuickSwipeViewAttachedPrivate::updateIsCurrent);
+ this, &QQuickSwipeViewAttachedPrivate::updateCurrentIndex);
connect(swipeView, &QQuickSwipeView::contentChildrenChanged,
this, &QQuickSwipeViewAttachedPrivate::updateIndex);
}
@@ -252,17 +315,26 @@ void QQuickSwipeViewAttachedPrivate::setView(QQuickSwipeView *view)
emit q->viewChanged();
updateIndex();
- updateIsCurrent();
+ updateCurrentIndex();
}
-void QQuickSwipeViewAttachedPrivate::setIsCurrent(bool current)
+void QQuickSwipeViewAttachedPrivate::setCurrentIndex(int i)
{
- if (current == isCurrent)
+ if (i == currentIndex)
return;
- isCurrent = current;
Q_Q(QQuickSwipeViewAttached);
- emit q->isCurrentItemChanged();
+ const bool wasCurrent = q->isCurrentItem();
+ const bool wasNext = q->isNextItem();
+ const bool wasPrevious = q->isPreviousItem();
+
+ currentIndex = i;
+ if (wasCurrent != q->isCurrentItem())
+ emit q->isCurrentItemChanged();
+ if (wasNext != q->isNextItem())
+ emit q->isNextItemChanged();
+ if (wasPrevious != q->isPreviousItem())
+ emit q->isPreviousItemChanged();
}
void QQuickSwipeViewAttachedPrivate::setIndex(int i)
@@ -316,15 +388,20 @@ void QQuickSwipeViewAttachedPrivate::itemDestroyed(QQuickItem *item)
QQuickItemPrivate::get(item)->removeItemChangeListener(this, QQuickItemPrivate::Parent | QQuickItemPrivate::Destroyed);
}
-QQuickSwipeViewAttached::QQuickSwipeViewAttached(QQuickItem *item) :
- QObject(*(new QQuickSwipeViewAttachedPrivate(item)), item)
+QQuickSwipeViewAttached::QQuickSwipeViewAttached(QObject *parent) :
+ QObject(*(new QQuickSwipeViewAttachedPrivate), parent)
{
Q_D(QQuickSwipeViewAttached);
- if (item->parentItem())
- d->updateView(item->parentItem());
-
- QQuickItemPrivate *p = QQuickItemPrivate::get(item);
- p->addItemChangeListener(d, QQuickItemPrivate::Parent | QQuickItemPrivate::Destroyed);
+ d->item = qobject_cast<QQuickItem *>(parent);
+ if (d->item) {
+ if (d->item->parentItem())
+ d->updateView(d->item->parentItem());
+
+ QQuickItemPrivate *p = QQuickItemPrivate::get(d->item);
+ p->addItemChangeListener(d, QQuickItemPrivate::Parent | QQuickItemPrivate::Destroyed);
+ } else if (parent) {
+ qmlInfo(parent) << "SwipeView: attached properties must be accessed from within a child item";
+ }
}
QQuickSwipeViewAttached::~QQuickSwipeViewAttached()
@@ -350,7 +427,19 @@ int QQuickSwipeViewAttached::index() const
bool QQuickSwipeViewAttached::isCurrentItem() const
{
Q_D(const QQuickSwipeViewAttached);
- return d->swipeView ? d->swipeView->currentIndex() == d->index : false;
+ return d->index != -1 && d->currentIndex != -1 && d->index == d->currentIndex;
+}
+
+bool QQuickSwipeViewAttached::isNextItem() const
+{
+ Q_D(const QQuickSwipeViewAttached);
+ return d->index != -1 && d->currentIndex != -1 && d->index == d->currentIndex + 1;
+}
+
+bool QQuickSwipeViewAttached::isPreviousItem() const
+{
+ Q_D(const QQuickSwipeViewAttached);
+ return d->index != -1 && d->currentIndex != -1 && d->index == d->currentIndex - 1;
}
QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquickswipeview_p.h b/src/quicktemplates2/qquickswipeview_p.h
index 49d3b840..e29d2b28 100644
--- a/src/quicktemplates2/qquickswipeview_p.h
+++ b/src/quicktemplates2/qquickswipeview_p.h
@@ -58,12 +58,19 @@ class QQuickSwipeViewPrivate;
class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipeView : public QQuickContainer
{
Q_OBJECT
+ Q_PROPERTY(bool interactive READ isInteractive WRITE setInteractive NOTIFY interactiveChanged FINAL REVISION 1)
public:
explicit QQuickSwipeView(QQuickItem *parent = nullptr);
+ bool isInteractive() const;
+ void setInteractive(bool interactive);
+
static QQuickSwipeViewAttached *qmlAttachedProperties(QObject *object);
+Q_SIGNALS:
+ Q_REVISION(1) void interactiveChanged();
+
protected:
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
void itemAdded(int index, QQuickItem *item) override;
@@ -80,19 +87,25 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickSwipeViewAttached : public QObject
Q_OBJECT
Q_PROPERTY(int index READ index NOTIFY indexChanged FINAL)
Q_PROPERTY(bool isCurrentItem READ isCurrentItem NOTIFY isCurrentItemChanged FINAL)
+ Q_PROPERTY(bool isNextItem READ isNextItem NOTIFY isNextItemChanged FINAL REVISION 1)
+ Q_PROPERTY(bool isPreviousItem READ isPreviousItem NOTIFY isPreviousItemChanged FINAL REVISION 1)
Q_PROPERTY(QQuickSwipeView *view READ view NOTIFY viewChanged FINAL)
public:
- explicit QQuickSwipeViewAttached(QQuickItem *delegateItem);
+ explicit QQuickSwipeViewAttached(QObject *parent = nullptr);
~QQuickSwipeViewAttached();
int index() const;
bool isCurrentItem() const;
+ bool isNextItem() const;
+ bool isPreviousItem() const;
QQuickSwipeView *view() const;
Q_SIGNALS:
void indexChanged();
void isCurrentItemChanged();
+ /*Q_REVISION(1)*/ void isNextItemChanged();
+ /*Q_REVISION(1)*/ void isPreviousItemChanged();
void viewChanged();
private:
diff --git a/src/quicktemplates2/qquicktextarea.cpp b/src/quicktemplates2/qquicktextarea.cpp
index 81552185..7c2e0f11 100644
--- a/src/quicktemplates2/qquicktextarea.cpp
+++ b/src/quicktemplates2/qquicktextarea.cpp
@@ -99,15 +99,39 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \qmlsignal QtQuick.Controls::TextArea::pressAndHold(MouseEvent mouse)
+ \qmlsignal QtQuick.Controls::TextArea::pressAndHold(MouseEvent event)
This signal is emitted when there is a long press (the delay depends on the platform plugin).
- The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
+ The \l {MouseEvent}{event} parameter provides information about the press, including the x and y
position of the press, and which button is pressed.
+
+ \sa pressed, released
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::TextArea::pressed(MouseEvent event)
+ \since QtQuick.Controls 2.1
+
+ This signal is emitted when the text area is pressed by the user.
+ The \l {MouseEvent}{event} parameter provides information about the press,
+ including the x and y position of the press, and which button is pressed.
+
+ \sa released, pressAndHold
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::TextArea::released(MouseEvent event)
+ \since QtQuick.Controls 2.1
+
+ This signal is emitted when the text area is released by the user.
+ The \l {MouseEvent}{event} parameter provides information about the release,
+ including the x and y position of the press, and which button is pressed.
+
+ \sa pressed, pressAndHold
*/
QQuickTextAreaPrivate::QQuickTextAreaPrivate()
- : background(nullptr), focusReason(Qt::OtherFocusReason), accessibleAttached(nullptr), flickable(nullptr)
+ : hovered(false), background(nullptr), focusReason(Qt::OtherFocusReason), accessibleAttached(nullptr), flickable(nullptr)
{
#ifndef QT_NO_ACCESSIBILITY
QAccessible::installActivationObserver(this);
@@ -158,7 +182,7 @@ void QQuickTextAreaPrivate::attachFlickable(QQuickFlickable *item)
QObject::connect(flickable, &QQuickFlickable::contentXChanged, q, &QQuickItem::update);
QObject::connect(flickable, &QQuickFlickable::contentYChanged, q, &QQuickItem::update);
- QQuickItemPrivate::get(flickable)->updateOrAddGeometryChangeListener(this, QQuickItemPrivate::SizeChange);
+ QQuickItemPrivate::get(flickable)->updateOrAddGeometryChangeListener(this, QQuickGeometryChange::Size);
QObjectPrivate::connect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl);
QObjectPrivate::connect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl);
@@ -178,7 +202,7 @@ void QQuickTextAreaPrivate::detachFlickable()
QObject::disconnect(flickable, &QQuickFlickable::contentXChanged, q, &QQuickItem::update);
QObject::disconnect(flickable, &QQuickFlickable::contentYChanged, q, &QQuickItem::update);
- QQuickItemPrivate::get(flickable)->updateOrRemoveGeometryChangeListener(this, QQuickItemPrivate::SizeChange);
+ QQuickItemPrivate::get(flickable)->updateOrRemoveGeometryChangeListener(this, QQuickGeometryChange::Size);
QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentWidthChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl);
QObjectPrivate::disconnect(flickable, &QQuickFlickable::contentHeightChanged, this, &QQuickTextAreaPrivate::resizeFlickableControl);
@@ -245,11 +269,11 @@ void QQuickTextAreaPrivate::resizeFlickableContent()
flickable->setContentHeight(q->contentHeight() + q->topPadding() + q->bottomPadding());
}
-void QQuickTextAreaPrivate::itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry)
+void QQuickTextAreaPrivate::itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff)
{
Q_UNUSED(item);
- Q_UNUSED(newGeometry);
- Q_UNUSED(oldGeometry);
+ Q_UNUSED(change);
+ Q_UNUSED(diff);
resizeFlickableControl();
}
@@ -283,6 +307,7 @@ QQuickTextArea::QQuickTextArea(QQuickItem *parent) :
{
Q_D(QQuickTextArea);
setActiveFocusOnTab(true);
+ setAcceptedMouseButtons(Qt::AllButtons);
d->setImplicitResizeEnabled(false);
d->pressHandler.control = this;
#ifndef QT_NO_CURSOR
@@ -474,6 +499,55 @@ void QQuickTextArea::setFocusReason(Qt::FocusReason reason)
emit focusReasonChanged();
}
+/*!
+ \since QtQuick.Controls 2.1
+ \qmlproperty bool QtQuick.Controls::TextArea::hovered
+ \readonly
+
+ This property holds whether the text area is hovered.
+
+ \sa hoverEnabled
+*/
+bool QQuickTextArea::isHovered() const
+{
+ Q_D(const QQuickTextArea);
+ return d->hovered;
+}
+
+void QQuickTextArea::setHovered(bool hovered)
+{
+ Q_D(QQuickTextArea);
+ if (hovered == d->hovered)
+ return;
+
+ d->hovered = hovered;
+ emit hoveredChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.1
+ \qmlproperty bool QtQuick.Controls::TextArea::hoverEnabled
+
+ This property determines whether the text area accepts hover events. The default value is \c true.
+
+ \sa hovered
+*/
+bool QQuickTextArea::isHoverEnabled() const
+{
+ Q_D(const QQuickTextArea);
+ return d->hoverEnabled;
+}
+
+void QQuickTextArea::setHoverEnabled(bool enabled)
+{
+ Q_D(QQuickTextArea);
+ if (enabled == d->hoverEnabled)
+ return;
+
+ setAcceptHoverEvents(enabled);
+ emit hoverEnabledChanged();
+}
+
bool QQuickTextArea::contains(const QPointF &point) const
{
Q_D(const QQuickTextArea);
@@ -554,6 +628,22 @@ void QQuickTextArea::focusOutEvent(QFocusEvent *event)
setFocusReason(event->reason());
}
+void QQuickTextArea::hoverEnterEvent(QHoverEvent *event)
+{
+ Q_D(QQuickTextArea);
+ QQuickTextEdit::hoverEnterEvent(event);
+ setHovered(d->hoverEnabled);
+ event->setAccepted(d->hoverEnabled);
+}
+
+void QQuickTextArea::hoverLeaveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickTextArea);
+ QQuickTextEdit::hoverLeaveEvent(event);
+ setHovered(false);
+ event->setAccepted(d->hoverEnabled);
+}
+
void QQuickTextArea::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickTextArea);
@@ -563,7 +653,12 @@ void QQuickTextArea::mousePressEvent(QMouseEvent *event)
QQuickTextEdit::mousePressEvent(d->pressHandler.delayedMousePressEvent);
d->pressHandler.clearDelayedMouseEvent();
}
+ // Calling the base class implementation will result in QQuickTextControl's
+ // press handler being called, which ignores events that aren't Qt::LeftButton.
+ const bool wasAccepted = event->isAccepted();
QQuickTextEdit::mousePressEvent(event);
+ if (wasAccepted)
+ event->accept();
}
}
diff --git a/src/quicktemplates2/qquicktextarea_p.h b/src/quicktemplates2/qquicktextarea_p.h
index f00943aa..20500ee6 100644
--- a/src/quicktemplates2/qquicktextarea_p.h
+++ b/src/quicktemplates2/qquicktextarea_p.h
@@ -67,6 +67,8 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTextArea : public QQuickTextEdit
Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL)
Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText NOTIFY placeholderTextChanged FINAL)
Q_PROPERTY(Qt::FocusReason focusReason READ focusReason WRITE setFocusReason NOTIFY focusReasonChanged FINAL)
+ Q_PROPERTY(bool hovered READ isHovered NOTIFY hoveredChanged FINAL REVISION 1)
+ Q_PROPERTY(bool hoverEnabled READ isHoverEnabled WRITE setHoverEnabled NOTIFY hoverEnabledChanged FINAL REVISION 1)
public:
explicit QQuickTextArea(QQuickItem *parent = nullptr);
@@ -86,6 +88,12 @@ public:
Qt::FocusReason focusReason() const;
void setFocusReason(Qt::FocusReason reason);
+ bool isHovered() const;
+ void setHovered(bool hovered);
+
+ bool isHoverEnabled() const;
+ void setHoverEnabled(bool enabled);
+
bool contains(const QPointF &point) const override;
Q_SIGNALS:
@@ -95,7 +103,11 @@ Q_SIGNALS:
void backgroundChanged();
void placeholderTextChanged();
void focusReasonChanged();
+ Q_REVISION(1) void hoveredChanged();
+ Q_REVISION(1) void hoverEnabledChanged();
void pressAndHold(QQuickMouseEvent *event);
+ Q_REVISION(1) void pressed(QQuickMouseEvent *event);
+ Q_REVISION(1) void released(QQuickMouseEvent *event);
protected:
void classBegin() override;
@@ -107,6 +119,8 @@ protected:
void focusInEvent(QFocusEvent *event) override;
void focusOutEvent(QFocusEvent *event) override;
+ void hoverEnterEvent(QHoverEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
diff --git a/src/quicktemplates2/qquicktextarea_p_p.h b/src/quicktemplates2/qquicktextarea_p_p.h
index 8af5d0d7..a9114054 100644
--- a/src/quicktemplates2/qquicktextarea_p_p.h
+++ b/src/quicktemplates2/qquicktextarea_p_p.h
@@ -87,7 +87,7 @@ public:
void resizeFlickableControl();
void resizeFlickableContent();
- void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
qreal getImplicitWidth() const override;
qreal getImplicitHeight() const override;
@@ -102,6 +102,7 @@ public:
QAccessible::Role accessibleRole() const override;
#endif
+ bool hovered;
QFont font;
QQuickItem *background;
QString placeholder;
diff --git a/src/quicktemplates2/qquicktextfield.cpp b/src/quicktemplates2/qquicktextfield.cpp
index 3b09b27b..88450e78 100644
--- a/src/quicktemplates2/qquicktextfield.cpp
+++ b/src/quicktemplates2/qquicktextfield.cpp
@@ -82,15 +82,40 @@ QT_BEGIN_NAMESPACE
*/
/*!
- \qmlsignal QtQuick.Controls::TextField::pressAndHold(MouseEvent mouse)
+ \qmlsignal QtQuick.Controls::TextField::pressAndHold(MouseEvent event)
This signal is emitted when there is a long press (the delay depends on the platform plugin).
- The \l {MouseEvent}{mouse} parameter provides information about the press, including the x and y
+ The \l {MouseEvent}{event} parameter provides information about the press, including the x and y
position of the press, and which button is pressed.
+
+ \sa pressed, released
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::TextField::pressed(MouseEvent event)
+ \since QtQuick.Controls 2.1
+
+ This signal is emitted when the text field is pressed by the user.
+ The \l {MouseEvent}{event} parameter provides information about the press,
+ including the x and y position of the press, and which button is pressed.
+
+ \sa released, pressAndHold
+*/
+
+/*!
+ \qmlsignal QtQuick.Controls::TextField::released(MouseEvent event)
+ \since QtQuick.Controls 2.1
+
+ This signal is emitted when the text field is released by the user.
+ The \l {MouseEvent}{event} parameter provides information about the release,
+ including the x and y position of the press, and which button is pressed.
+
+ \sa pressed, pressAndHold
*/
QQuickTextFieldPrivate::QQuickTextFieldPrivate()
- : background(nullptr)
+ : hovered(false)
+ , background(nullptr)
, focusReason(Qt::OtherFocusReason)
, accessibleAttached(nullptr)
{
@@ -152,6 +177,7 @@ QQuickTextField::QQuickTextField(QQuickItem *parent) :
Q_D(QQuickTextField);
d->pressHandler.control = this;
d->setImplicitResizeEnabled(false);
+ setAcceptedMouseButtons(Qt::AllButtons);
setActiveFocusOnTab(true);
#ifndef QT_NO_CURSOR
setCursor(Qt::IBeamCursor);
@@ -350,6 +376,55 @@ void QQuickTextField::setFocusReason(Qt::FocusReason reason)
emit focusReasonChanged();
}
+/*!
+ \since QtQuick.Controls 2.1
+ \qmlproperty bool QtQuick.Controls::TextField::hovered
+ \readonly
+
+ This property holds whether the text field is hovered.
+
+ \sa hoverEnabled
+*/
+bool QQuickTextField::isHovered() const
+{
+ Q_D(const QQuickTextField);
+ return d->hovered;
+}
+
+void QQuickTextField::setHovered(bool hovered)
+{
+ Q_D(QQuickTextField);
+ if (hovered == d->hovered)
+ return;
+
+ d->hovered = hovered;
+ emit hoveredChanged();
+}
+
+/*!
+ \since QtQuick.Controls 2.1
+ \qmlproperty bool QtQuick.Controls::TextField::hoverEnabled
+
+ This property determines whether the text field accepts hover events. The default value is \c false.
+
+ \sa hovered
+*/
+bool QQuickTextField::isHoverEnabled() const
+{
+ Q_D(const QQuickTextField);
+ return d->hoverEnabled;
+}
+
+void QQuickTextField::setHoverEnabled(bool enabled)
+{
+ Q_D(QQuickTextField);
+ if (enabled == d->hoverEnabled)
+ return;
+
+ setAcceptHoverEvents(enabled);
+ emit hoverEnabledChanged();
+}
+
void QQuickTextField::classBegin()
{
Q_D(QQuickTextField);
@@ -410,6 +485,22 @@ void QQuickTextField::focusOutEvent(QFocusEvent *event)
setFocusReason(event->reason());
}
+void QQuickTextField::hoverEnterEvent(QHoverEvent *event)
+{
+ Q_D(QQuickTextField);
+ QQuickTextInput::hoverEnterEvent(event);
+ setHovered(d->hoverEnabled);
+ event->setAccepted(d->hoverEnabled);
+}
+
+void QQuickTextField::hoverLeaveEvent(QHoverEvent *event)
+{
+ Q_D(QQuickTextField);
+ QQuickTextInput::hoverLeaveEvent(event);
+ setHovered(false);
+ event->setAccepted(d->hoverEnabled);
+}
+
void QQuickTextField::mousePressEvent(QMouseEvent *event)
{
Q_D(QQuickTextField);
diff --git a/src/quicktemplates2/qquicktextfield_p.h b/src/quicktemplates2/qquicktextfield_p.h
index 591d6edd..5ef7a02d 100644
--- a/src/quicktemplates2/qquicktextfield_p.h
+++ b/src/quicktemplates2/qquicktextfield_p.h
@@ -66,6 +66,8 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTextField : public QQuickTextInput
Q_PROPERTY(QQuickItem *background READ background WRITE setBackground NOTIFY backgroundChanged FINAL)
Q_PROPERTY(QString placeholderText READ placeholderText WRITE setPlaceholderText NOTIFY placeholderTextChanged FINAL)
Q_PROPERTY(Qt::FocusReason focusReason READ focusReason WRITE setFocusReason NOTIFY focusReasonChanged FINAL)
+ Q_PROPERTY(bool hovered READ isHovered NOTIFY hoveredChanged FINAL REVISION 1)
+ Q_PROPERTY(bool hoverEnabled READ isHoverEnabled WRITE setHoverEnabled NOTIFY hoverEnabledChanged FINAL REVISION 1)
public:
explicit QQuickTextField(QQuickItem *parent = nullptr);
@@ -83,6 +85,12 @@ public:
Qt::FocusReason focusReason() const;
void setFocusReason(Qt::FocusReason reason);
+ bool isHovered() const;
+ void setHovered(bool hovered);
+
+ bool isHoverEnabled() const;
+ void setHoverEnabled(bool enabled);
+
Q_SIGNALS:
void fontChanged();
void implicitWidthChanged3();
@@ -90,7 +98,11 @@ Q_SIGNALS:
void backgroundChanged();
void placeholderTextChanged();
void focusReasonChanged();
- void pressAndHold(QQuickMouseEvent *mouse);
+ Q_REVISION(1) void hoveredChanged();
+ Q_REVISION(1) void hoverEnabledChanged();
+ void pressAndHold(QQuickMouseEvent *event);
+ Q_REVISION(1) void pressed(QQuickMouseEvent *event);
+ Q_REVISION(1) void released(QQuickMouseEvent *event);
protected:
void classBegin() override;
@@ -102,6 +114,8 @@ protected:
void focusInEvent(QFocusEvent *event) override;
void focusOutEvent(QFocusEvent *event) override;
+ void hoverEnterEvent(QHoverEvent *event) override;
+ void hoverLeaveEvent(QHoverEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override;
diff --git a/src/quicktemplates2/qquicktextfield_p_p.h b/src/quicktemplates2/qquicktextfield_p_p.h
index 293b53de..dd355145 100644
--- a/src/quicktemplates2/qquicktextfield_p_p.h
+++ b/src/quicktemplates2/qquicktextfield_p_p.h
@@ -93,6 +93,7 @@ public:
QAccessible::Role accessibleRole() const override;
#endif
+ bool hovered;
QFont font;
QQuickItem *background;
QString placeholder;
diff --git a/src/quicktemplates2/qquicktoolseparator.cpp b/src/quicktemplates2/qquicktoolseparator.cpp
new file mode 100644
index 00000000..36c5ac12
--- /dev/null
+++ b/src/quicktemplates2/qquicktoolseparator.cpp
@@ -0,0 +1,146 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquicktoolseparator_p.h"
+
+#include "qquickcontrol_p_p.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \qmltype ToolSeparator
+ \inherits Control
+ \instantiates QQuickToolSeparator
+ \inqmlmodule QtQuick.Controls
+ \since 5.8
+ \ingroup qtquickcontrols2-separators
+ \brief Separates a group of items in a toolbar from adjacent items.
+
+ ToolSeparator is used to visually distinguish between groups of items in a
+ toolbar by separating them with a line. It can be used in horizontal or
+ vertical toolbars by setting the \l orientation property to \c Qt.Vertical
+ or \c Qt.Horizontal, respectively.
+
+ \image qtquickcontrols2-toolseparator.png
+
+ \snippet qtquickcontrols2-toolseparator.qml 1
+
+ \sa {Customizing ToolSeparator}, {Separator Controls}
+*/
+
+class QQuickToolSeparatorPrivate : public QQuickControlPrivate
+{
+ Q_DECLARE_PUBLIC(QQuickToolSeparator)
+
+public:
+ QQuickToolSeparatorPrivate() :
+ orientation(Qt::Vertical)
+ {
+ }
+
+ Qt::Orientation orientation;
+};
+
+QQuickToolSeparator::QQuickToolSeparator(QQuickItem *parent) :
+ QQuickControl(*(new QQuickToolSeparatorPrivate), parent)
+{
+}
+
+/*!
+ \qmlproperty enumeration QtQuick.Controls::ToolSeparator::orientation
+
+ This property holds the orientation of the tool separator.
+
+ Possible values:
+ \value Qt.Horizontal A horizontal separator is used in a vertical toolbar.
+ \value Qt.Vertical A vertical separator is used in a horizontal toolbar. (default)
+*/
+Qt::Orientation QQuickToolSeparator::orientation() const
+{
+ Q_D(const QQuickToolSeparator);
+ return d->orientation;
+}
+
+void QQuickToolSeparator::setOrientation(Qt::Orientation orientation)
+{
+ Q_D(QQuickToolSeparator);
+ if (d->orientation == orientation)
+ return;
+
+ d->orientation = orientation;
+ emit orientationChanged();
+}
+
+/*!
+ \readonly
+ \qmlproperty bool QtQuick.Controls::ToolSeparator::horizontal
+
+ This property holds whether \l orientation is equal to \c Qt.Horizontal.
+
+ It is useful for \l {Customizing ToolSeparator}{customizing ToolSeparator}.
+
+ \sa orientation, vertical
+*/
+bool QQuickToolSeparator::isHorizontal() const
+{
+ Q_D(const QQuickToolSeparator);
+ return d->orientation == Qt::Horizontal;
+}
+
+/*!
+ \readonly
+ \qmlproperty bool QtQuick.Controls::ToolSeparator::vertical
+
+ This property holds whether \l orientation is equal to \c Qt.Vertical.
+
+ It is useful for \l {Customizing ToolSeparator}{customizing ToolSeparator}.
+
+ \sa orientation, horizontal
+*/
+bool QQuickToolSeparator::isVertical() const
+{
+ Q_D(const QQuickToolSeparator);
+ return d->orientation == Qt::Vertical;
+}
+
+#ifndef QT_NO_ACCESSIBILITY
+QAccessible::Role QQuickToolSeparator::accessibleRole() const
+{
+ return QAccessible::Separator;
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/quicktemplates2/qquicktoolseparator_p.h b/src/quicktemplates2/qquicktoolseparator_p.h
new file mode 100644
index 00000000..c3376c22
--- /dev/null
+++ b/src/quicktemplates2/qquicktoolseparator_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTOOLSEPARATOR_P_H
+#define QQUICKTOOLSEPARATOR_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuickTemplates2/private/qquickcontrol_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickToolSeparatorPrivate;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickToolSeparator : public QQuickControl
+{
+ Q_OBJECT
+ Q_PROPERTY(Qt::Orientation orientation READ orientation WRITE setOrientation NOTIFY orientationChanged FINAL)
+ Q_PROPERTY(bool horizontal READ isHorizontal NOTIFY orientationChanged FINAL)
+ Q_PROPERTY(bool vertical READ isVertical NOTIFY orientationChanged FINAL)
+
+public:
+ explicit QQuickToolSeparator(QQuickItem *parent = nullptr);
+
+ Qt::Orientation orientation() const;
+ void setOrientation(Qt::Orientation orientation);
+
+ bool isHorizontal() const;
+ bool isVertical() const;
+
+Q_SIGNALS:
+ void orientationChanged();
+
+protected:
+#ifndef QT_NO_ACCESSIBILITY
+ QAccessible::Role accessibleRole() const override;
+#endif
+
+private:
+ Q_DISABLE_COPY(QQuickToolSeparator)
+ Q_DECLARE_PRIVATE(QQuickToolSeparator)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickToolSeparator)
+
+#endif // QQUICKTOOLSEPARATOR_P_H
diff --git a/src/quicktemplates2/qquicktooltip.cpp b/src/quicktemplates2/qquicktooltip.cpp
index cc0b6350..6b51de95 100644
--- a/src/quicktemplates2/qquicktooltip.cpp
+++ b/src/quicktemplates2/qquicktooltip.cpp
@@ -163,9 +163,8 @@ void QQuickToolTipPrivate::stopTimeout()
QQuickToolTip::QQuickToolTip(QQuickItem *parent) :
QQuickPopup(*(new QQuickToolTipPrivate), parent)
{
- Q_D(QQuickToolTip);
- d->allowVerticalFlip = true;
- d->allowHorizontalFlip = true;
+ setAllowVerticalFlip(true);
+ setAllowHorizontalFlip(true);
}
/*!
@@ -246,11 +245,7 @@ void QQuickToolTip::setTimeout(int timeout)
QQuickToolTipAttached *QQuickToolTip::qmlAttachedProperties(QObject *object)
{
- QQuickItem *item = qobject_cast<QQuickItem *>(object);
- if (!item)
- qmlInfo(object) << "ToolTip must be attached to an Item";
-
- return new QQuickToolTipAttached(item);
+ return new QQuickToolTipAttached(object);
}
void QQuickToolTip::open()
@@ -331,7 +326,7 @@ QQuickToolTip *QQuickToolTipAttachedPrivate::instance(bool create) const
QQmlContext *context = qmlContext(parent);
if (context) {
QQmlComponent component(context->engine());
- component.setData("import QtQuick.Controls 2.0; ToolTip { }", QUrl());
+ component.setData("import QtQuick.Controls 2.1; ToolTip { }", QUrl());
QObject *object = component.create(context);
tip = qobject_cast<QQuickToolTip *>(object);
@@ -342,9 +337,12 @@ QQuickToolTip *QQuickToolTipAttachedPrivate::instance(bool create) const
return tip;
}
-QQuickToolTipAttached::QQuickToolTipAttached(QQuickItem *item) :
- QObject(*(new QQuickToolTipAttachedPrivate), item)
+QQuickToolTipAttached::QQuickToolTipAttached(QObject *parent) :
+ QObject(*(new QQuickToolTipAttachedPrivate), parent)
{
+ QQuickItem *item = qobject_cast<QQuickItem *>(parent);
+ if (!item && parent)
+ qmlInfo(parent) << "ToolTip must be attached to an Item";
}
/*!
diff --git a/src/quicktemplates2/qquicktooltip_p.h b/src/quicktemplates2/qquicktooltip_p.h
index 227c6a4e..96c75c3b 100644
--- a/src/quicktemplates2/qquicktooltip_p.h
+++ b/src/quicktemplates2/qquicktooltip_p.h
@@ -111,7 +111,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickToolTipAttached : public QObject
Q_PROPERTY(QQuickToolTip *toolTip READ toolTip CONSTANT FINAL)
public:
- explicit QQuickToolTipAttached(QQuickItem *item);
+ explicit QQuickToolTipAttached(QObject *parent = nullptr);
QString text() const;
void setText(const QString &text);
diff --git a/src/quicktemplates2/qquicktumbler.cpp b/src/quicktemplates2/qquicktumbler.cpp
index 580859ef..82188df8 100644
--- a/src/quicktemplates2/qquicktumbler.cpp
+++ b/src/quicktemplates2/qquicktumbler.cpp
@@ -36,8 +36,10 @@
#include "qquicktumbler_p.h"
+#include <QtQml/qqmlinfo.h>
#include <QtQuick/private/qquickflickable_p.h>
#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
+#include <QtQuickTemplates2/private/qquicktumbler_p_p.h>
QT_BEGIN_NAMESPACE
@@ -57,53 +59,50 @@ QT_BEGIN_NAMESPACE
}
\endcode
- \section1 Non-wrapping Tumbler
+ Tumbler allows the user to select an option from a spinnable \e "wheel" of
+ items. It is useful for when there are too many options to use, for
+ example, a RadioButton, and too few options to require the use of an
+ editable SpinBox. It is convenient in that it requires no keyboard usage
+ and wraps around at each end when there are a large number of items.
- The default contentItem of Tumbler is a \l PathView, which wraps when it
- reaches the top and bottom. To achieve a non-wrapping Tumbler, use ListView
- as the contentItem:
+ The API is similar to that of views like \l ListView and \l PathView; a
+ \l model and \l delegate can be set, and the \l count and \l currentItem
+ properties provide read-only access to information about the view.
- \snippet tst_tumbler.qml contentItem
+ Unlike views like \l PathView and \l ListView, however, there is always a
+ current item (when the model isn't empty). This means that when \l count is
+ equal to \c 0, \l currentIndex will be \c -1. In all other cases, it will
+ be greater than or equal to \c 0.
+
+ By default, Tumbler \l {wrap}{wraps} when it reaches the top and bottom, as
+ long as there are more items in the model than there are visible items;
+ that is, when \l count is greater than \l visibleItemCount:
+
+ \snippet qtquickcontrols2-tumbler-timePicker.qml tumbler
\image qtquickcontrols2-tumbler-wrap.gif
\sa {Customizing Tumbler}, {Input Controls}
*/
-class QQuickTumblerPrivate : public QQuickControlPrivate, public QQuickItemChangeListener
+QQuickTumblerPrivate::QQuickTumblerPrivate() :
+ delegate(nullptr),
+ visibleItemCount(5),
+ wrap(true),
+ explicitWrap(false),
+ ignoreWrapChanges(false),
+ view(nullptr),
+ viewContentItem(nullptr),
+ viewContentItemType(UnsupportedContentItemType),
+ currentIndex(-1),
+ pendingCurrentIndex(-1),
+ ignoreCurrentIndexChanges(false),
+ count(0)
{
- Q_DECLARE_PUBLIC(QQuickTumbler)
-
-public:
- QQuickTumblerPrivate() :
- delegate(nullptr),
- visibleItemCount(3)
- {
- }
-
- ~QQuickTumblerPrivate()
- {
- }
-
- QVariant model;
- QQmlComponent *delegate;
- int visibleItemCount;
-
- void _q_updateItemHeights();
- void _q_updateItemWidths();
-
- void itemChildAdded(QQuickItem *, QQuickItem *) override;
- void itemChildRemoved(QQuickItem *, QQuickItem *) override;
-};
+}
-static QList<QQuickItem *> contentItemChildItems(QQuickItem *contentItem)
+QQuickTumblerPrivate::~QQuickTumblerPrivate()
{
- if (!contentItem)
- return QList<QQuickItem *>();
-
- // PathView has no contentItem property, but ListView does.
- QQuickFlickable *flickable = qobject_cast<QQuickFlickable *>(contentItem);
- return flickable ? flickable->contentItem()->childItems() : contentItem->childItems();
}
namespace {
@@ -111,44 +110,55 @@ namespace {
{
return tumbler->availableHeight() / tumbler->visibleItemCount();
}
+}
- enum ContentItemType {
- UnsupportedContentItemType,
- PathViewContentItem,
- ListViewContentItem
- };
-
- static inline QQuickItem *actualContentItem(QQuickItem *rootContentItem, ContentItemType contentType)
- {
- if (contentType == PathViewContentItem)
- return rootContentItem;
- else if (contentType == ListViewContentItem)
- return qobject_cast<QQuickFlickable*>(rootContentItem)->contentItem();
-
- return nullptr;
+/*
+ Finds the contentItem of the view that is a child of the control's \a contentItem.
+ The type is stored in \a type.
+*/
+QQuickItem *QQuickTumblerPrivate::determineViewType(QQuickItem *contentItem)
+{
+ if (contentItem->inherits("QQuickPathView")) {
+ view = contentItem;
+ viewContentItem = contentItem;
+ viewContentItemType = PathViewContentItem;
+ return contentItem;
+ } else if (contentItem->inherits("QQuickListView")) {
+ view = contentItem;
+ viewContentItem = qobject_cast<QQuickFlickable*>(contentItem)->contentItem();
+ viewContentItemType = ListViewContentItem;
+ return contentItem;
+ } else {
+ const auto childItems = contentItem->childItems();
+ for (QQuickItem *childItem : childItems) {
+ QQuickItem *item = determineViewType(childItem);
+ if (item)
+ return item;
+ }
}
- static inline ContentItemType contentItemType(QQuickItem *rootContentItem)
- {
- if (rootContentItem->inherits("QQuickPathView"))
- return PathViewContentItem;
- else if (rootContentItem->inherits("QQuickListView"))
- return ListViewContentItem;
+ resetViewData();
+ return nullptr;
+}
- return UnsupportedContentItemType;
- }
+void QQuickTumblerPrivate::resetViewData()
+{
+ view = nullptr;
+ viewContentItem = nullptr;
+ viewContentItemType = UnsupportedContentItemType;
+}
- static inline ContentItemType contentItemTypeFromDelegate(QQuickItem *delegateItem)
- {
- if (delegateItem->parentItem()->inherits("QQuickPathView")) {
- return PathViewContentItem;
- } else if (delegateItem->parentItem()->parentItem()
- && delegateItem->parentItem()->parentItem()->inherits("QQuickListView")) {
- return ListViewContentItem;
- }
+QList<QQuickItem *> QQuickTumblerPrivate::viewContentItemChildItems() const
+{
+ if (!viewContentItem)
+ return QList<QQuickItem *>();
- return UnsupportedContentItemType;
- }
+ return viewContentItem->childItems();
+}
+
+QQuickTumblerPrivate *QQuickTumblerPrivate::get(QQuickTumbler *tumbler)
+{
+ return tumbler->d_func();
}
void QQuickTumblerPrivate::_q_updateItemHeights()
@@ -157,7 +167,7 @@ void QQuickTumblerPrivate::_q_updateItemHeights()
// which doesn't affect them, only their getters.
Q_Q(const QQuickTumbler);
const qreal itemHeight = delegateHeight(q);
- const auto items = contentItemChildItems(contentItem);
+ const auto items = viewContentItemChildItems();
for (QQuickItem *childItem : items)
childItem->setHeight(itemHeight);
}
@@ -166,11 +176,49 @@ void QQuickTumblerPrivate::_q_updateItemWidths()
{
Q_Q(const QQuickTumbler);
const qreal availableWidth = q->availableWidth();
- const auto items = contentItemChildItems(contentItem);
+ const auto items = viewContentItemChildItems();
for (QQuickItem *childItem : items)
childItem->setWidth(availableWidth);
}
+void QQuickTumblerPrivate::_q_onViewCurrentIndexChanged()
+{
+ Q_Q(QQuickTumbler);
+ if (view && !ignoreCurrentIndexChanges) {
+ const int oldCurrentIndex = currentIndex;
+ currentIndex = view->property("currentIndex").toInt();
+ if (oldCurrentIndex != currentIndex)
+ emit q->currentIndexChanged();
+ }
+}
+
+void QQuickTumblerPrivate::_q_onViewCountChanged()
+{
+ Q_Q(QQuickTumbler);
+
+ setCount(view->property("count").toInt());
+
+ if (count > 0) {
+ if (pendingCurrentIndex != -1) {
+ // If there was an attempt to set currentIndex at creation, try to finish that attempt now.
+ // componentComplete() is too early, because the count might only be known sometime after completion.
+ q->setCurrentIndex(pendingCurrentIndex);
+ // If we could successfully set the currentIndex, consider it done.
+ // Otherwise, we'll try again later in updatePolish().
+ if (currentIndex == pendingCurrentIndex)
+ pendingCurrentIndex = -1;
+ else
+ q->polish();
+ } else if (currentIndex == -1) {
+ // If new items were added and our currentIndex was -1, we must
+ // enforce our rule of a non-negative currentIndex when count > 0.
+ q->setCurrentIndex(0);
+ }
+ } else {
+ q->setCurrentIndex(-1);
+ }
+}
+
void QQuickTumblerPrivate::itemChildAdded(QQuickItem *, QQuickItem *)
{
_q_updateItemWidths();
@@ -196,6 +244,9 @@ QQuickTumbler::QQuickTumbler(QQuickItem *parent) :
QQuickTumbler::~QQuickTumbler()
{
+ Q_D(QQuickTumbler);
+ // Ensure that the item change listener is removed.
+ d->disconnectFromView();
}
/*!
@@ -215,8 +266,17 @@ void QQuickTumbler::setModel(const QVariant &model)
if (model == d->model)
return;
+ d->lockWrap();
+
d->model = model;
emit modelChanged();
+
+ d->unlockWrap();
+
+ // Don't try to correct the currentIndex if count() isn't known yet.
+ // We can check in setupViewData() instead.
+ if (isComponentComplete() && d->view && count() == 0)
+ setCurrentIndex(-1);
}
/*!
@@ -228,24 +288,67 @@ void QQuickTumbler::setModel(const QVariant &model)
int QQuickTumbler::count() const
{
Q_D(const QQuickTumbler);
- return d->contentItem->property("count").toInt();
+ return d->count;
}
/*!
\qmlproperty int QtQuick.Controls::Tumbler::currentIndex
This property holds the index of the current item.
+
+ The value of this property is \c -1 when \l count is equal to \c 0. In all
+ other cases, it will be greater than or equal to \c 0.
*/
int QQuickTumbler::currentIndex() const
{
Q_D(const QQuickTumbler);
- return d->contentItem ? d->contentItem->property("currentIndex").toInt() : -1;
+ return d->currentIndex;
}
void QQuickTumbler::setCurrentIndex(int currentIndex)
{
Q_D(QQuickTumbler);
- d->contentItem->setProperty("currentIndex", currentIndex);
+ if (currentIndex == d->currentIndex || currentIndex < -1)
+ return;
+
+ if (!isComponentComplete()) {
+ // Views can't set currentIndex until they're ready.
+ d->pendingCurrentIndex = currentIndex;
+ return;
+ }
+
+ // -1 doesn't make sense for a non-empty Tumbler, because unlike
+ // e.g. ListView, there's always one item selected.
+ // Wait until the component has finished before enforcing this rule, though,
+ // because the count might not be known yet.
+ if ((d->count > 0 && currentIndex == -1) || (currentIndex >= d->count)) {
+ return;
+ }
+
+ // The view might not have been created yet, as is the case
+ // if you create a Tumbler component and pass e.g. { currentIndex: 2 }
+ // to createObject().
+ if (d->view) {
+ // Only actually set our currentIndex if the view was able to set theirs.
+ bool couldSet = false;
+ if (d->count == 0 && currentIndex == -1) {
+ // PathView insists on using 0 as the currentIndex when there are no items.
+ couldSet = true;
+ } else {
+ d->ignoreCurrentIndexChanges = true;
+ d->view->setProperty("currentIndex", currentIndex);
+ d->ignoreCurrentIndexChanges = false;
+
+ couldSet = d->view->property("currentIndex").toInt() == currentIndex;
+ }
+
+ if (couldSet) {
+ // The view's currentIndex might not have actually changed, but ours has,
+ // and that's what user code sees.
+ d->currentIndex = currentIndex;
+ emit currentIndexChanged();
+ }
+ }
}
/*!
@@ -257,7 +360,7 @@ void QQuickTumbler::setCurrentIndex(int currentIndex)
QQuickItem *QQuickTumbler::currentItem() const
{
Q_D(const QQuickTumbler);
- return d->contentItem ? d->contentItem->property("currentItem").value<QQuickItem*>() : nullptr;
+ return d->view ? d->view->property("currentItem").value<QQuickItem*>() : nullptr;
}
/*!
@@ -304,15 +407,41 @@ void QQuickTumbler::setVisibleItemCount(int visibleItemCount)
emit visibleItemCountChanged();
}
-QQuickTumblerAttached *QQuickTumbler::qmlAttachedProperties(QObject *object)
+/*!
+ \qmlproperty bool QtQuick.Controls::Tumbler::wrap
+ \since QtQuick.Controls 2.1
+
+ This property determines whether or not the tumbler wraps around when it
+ reaches the top or bottom.
+
+ The default value is \c false when \l count is less than
+ \l visibleItemCount, as it is simpler to interact with a non-wrapping Tumbler
+ when there are only a few items. To override this behavior, explicitly set
+ the value of this property. To return to the default behavior, set this
+ property to \c undefined.
+*/
+bool QQuickTumbler::wrap() const
{
- QQuickItem *delegateItem = qobject_cast<QQuickItem *>(object);
- if (!delegateItem) {
- qWarning() << "Tumbler: attached properties of Tumbler must be accessed from within a delegate item";
- return nullptr;
- }
+ Q_D(const QQuickTumbler);
+ return d->wrap;
+}
+
+void QQuickTumbler::setWrap(bool wrap)
+{
+ Q_D(QQuickTumbler);
+ d->setWrap(wrap, true);
+}
+
+void QQuickTumbler::resetWrap()
+{
+ Q_D(QQuickTumbler);
+ d->explicitWrap = false;
+ d->setWrapBasedOnCount();
+}
- return new QQuickTumblerAttached(delegateItem);
+QQuickTumblerAttached *QQuickTumbler::qmlAttachedProperties(QObject *object)
+{
+ return new QQuickTumblerAttached(object);
}
void QQuickTumbler::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
@@ -333,6 +462,13 @@ void QQuickTumbler::componentComplete()
QQuickControl::componentComplete();
d->_q_updateItemHeights();
d->_q_updateItemWidths();
+
+ if (!d->view) {
+ // Force the view to be created.
+ emit wrapChanged();
+ // Determine the type of view for attached properties, etc.
+ d->setupViewData(d->contentItem);
+ }
}
void QQuickTumbler::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
@@ -341,59 +477,189 @@ void QQuickTumbler::contentItemChange(QQuickItem *newItem, QQuickItem *oldItem)
QQuickControl::contentItemChange(newItem, oldItem);
- // Since we use the currentIndex of the contentItem directly, we must
- // ensure that we keep track of the currentIndex so it doesn't get lost
- // between contentItem changes.
- const int previousCurrentIndex = currentIndex();
-
- if (oldItem) {
- disconnect(oldItem, SIGNAL(currentIndexChanged()), this, SIGNAL(currentIndexChanged()));
- disconnect(oldItem, SIGNAL(currentItemChanged()), this, SIGNAL(currentItemChanged()));
- disconnect(oldItem, SIGNAL(countChanged()), this, SIGNAL(countChanged()));
-
- ContentItemType oldContentItemType = contentItemType(oldItem);
- QQuickItem *actualOldContentItem = actualContentItem(oldItem, oldContentItemType);
- QQuickItemPrivate *actualContentItemPrivate = QQuickItemPrivate::get(actualOldContentItem);
- actualContentItemPrivate->removeItemChangeListener(d, QQuickItemPrivate::Children);
- }
+ if (oldItem)
+ d->disconnectFromView();
if (newItem) {
- ContentItemType contentType = contentItemType(newItem);
- if (contentType == UnsupportedContentItemType) {
- qWarning() << "Tumbler: contentItems other than PathView and ListView are not supported";
- return;
+ // We wait until wrap is set to that we know which type of view to create.
+ // If we try to set up the view too early, we'll issue warnings about it not existing.
+ if (isComponentComplete()) {
+ // Make sure we use the new content item and not the current one, as that won't
+ // be changed until after contentItemChange() has finished.
+ d->setupViewData(newItem);
}
+ }
+}
- connect(newItem, SIGNAL(currentIndexChanged()), this, SIGNAL(currentIndexChanged()));
- connect(newItem, SIGNAL(currentItemChanged()), this, SIGNAL(currentItemChanged()));
- connect(newItem, SIGNAL(countChanged()), this, SIGNAL(countChanged()));
+void QQuickTumblerPrivate::disconnectFromView()
+{
+ Q_Q(QQuickTumbler);
+ if (!view) {
+ // If a custom content item is declared, it can happen that
+ // the original contentItem exists without the view etc. having been
+ // determined yet, and then this is called when the custom content item
+ // is eventually set.
+ return;
+ }
- QQuickItem *actualNewContentItem = actualContentItem(newItem, contentType);
- QQuickItemPrivate *actualContentItemPrivate = QQuickItemPrivate::get(actualNewContentItem);
- actualContentItemPrivate->addItemChangeListener(d, QQuickItemPrivate::Children);
+ QObject::disconnect(view, SIGNAL(currentIndexChanged()), q, SLOT(_q_onViewCurrentIndexChanged()));
+ QObject::disconnect(view, SIGNAL(currentItemChanged()), q, SIGNAL(currentItemChanged()));
+ QObject::disconnect(view, SIGNAL(countChanged()), q, SLOT(_q_onViewCountChanged()));
- // If the previous currentIndex is -1, it means we had no contentItem previously.
- if (previousCurrentIndex != -1) {
- // Can't call setCurrentIndex here, as contentItemChange() is
- // called *before* the contentItem is set.
- newItem->setProperty("currentIndex", previousCurrentIndex);
- }
+ QQuickItemPrivate *oldViewContentItemPrivate = QQuickItemPrivate::get(viewContentItem);
+ oldViewContentItemPrivate->removeItemChangeListener(this, QQuickItemPrivate::Children);
+
+ resetViewData();
+}
+
+void QQuickTumblerPrivate::setupViewData(QQuickItem *newControlContentItem)
+{
+ // Don't do anything if we've already set up.
+ if (view)
+ return;
+
+ determineViewType(newControlContentItem);
+
+ if (viewContentItemType == QQuickTumblerPrivate::UnsupportedContentItemType) {
+ qWarning() << "Tumbler: contentItem must contain either a PathView or a ListView";
+ return;
}
+
+ Q_Q(QQuickTumbler);
+ QObject::connect(view, SIGNAL(currentIndexChanged()), q, SLOT(_q_onViewCurrentIndexChanged()));
+ QObject::connect(view, SIGNAL(currentItemChanged()), q, SIGNAL(currentItemChanged()));
+ QObject::connect(view, SIGNAL(countChanged()), q, SLOT(_q_onViewCountChanged()));
+
+ QQuickItemPrivate *viewContentItemPrivate = QQuickItemPrivate::get(viewContentItem);
+ viewContentItemPrivate->addItemChangeListener(this, QQuickItemPrivate::Children);
+
+ // Sync the view's currentIndex with ours.
+ syncCurrentIndex();
}
-void QQuickTumbler::keyPressEvent(QKeyEvent *event)
+void QQuickTumblerPrivate::syncCurrentIndex()
{
- Q_D(QQuickTumbler);
+ const int actualViewIndex = view->property("currentIndex").toInt();
+ Q_Q(QQuickTumbler);
+
+ // Nothing to do.
+ if (actualViewIndex == currentIndex)
+ return;
+
+ // PathView likes to use 0 as currentIndex for empty models, but we use -1 for that.
+ if (q->count() == 0 && actualViewIndex == 0)
+ return;
+
+ ignoreCurrentIndexChanges = true;
+ view->setProperty("currentIndex", currentIndex);
+ ignoreCurrentIndexChanges = false;
+}
+
+void QQuickTumblerPrivate::setCount(int newCount)
+{
+ if (newCount == count)
+ return;
+
+ count = newCount;
+
+ Q_Q(QQuickTumbler);
+ setWrapBasedOnCount();
+
+ emit q->countChanged();
+}
+
+void QQuickTumblerPrivate::setWrapBasedOnCount()
+{
+ if (count == 0 || explicitWrap || ignoreWrapChanges)
+ return;
+
+ setWrap(count >= visibleItemCount, false);
+}
+
+void QQuickTumblerPrivate::setWrap(bool shouldWrap, bool isExplicit)
+{
+ if (isExplicit)
+ explicitWrap = true;
+
+ Q_Q(QQuickTumbler);
+ if (q->isComponentComplete() && shouldWrap == wrap)
+ return;
+
+ // Since we use the currentIndex of the contentItem directly, we must
+ // ensure that we keep track of the currentIndex so it doesn't get lost
+ // between view changes.
+ const int oldCurrentIndex = currentIndex;
+ disconnectFromView();
+
+ wrap = shouldWrap;
+
+ // New views will set their currentIndex upon creation, which we'd otherwise
+ // take as the correct one, so we must ignore them.
+ ignoreCurrentIndexChanges = true;
+
+ // This will cause the view to be created if our contentItem is a TumblerView.
+ emit q->wrapChanged();
+
+ ignoreCurrentIndexChanges = false;
+
+ // The view should have been created now, so we can start determining its type, etc.
+ // If the delegates use attached properties, this will have already been called,
+ // in which case it will return early. If the delegate doesn't use attached properties,
+ // we need to call it here.
+ setupViewData(contentItem);
+
+ q->setCurrentIndex(oldCurrentIndex);
+}
+
+void QQuickTumblerPrivate::lockWrap()
+{
+ ignoreWrapChanges = true;
+}
+
+void QQuickTumblerPrivate::unlockWrap()
+{
+ ignoreWrapChanges = false;
+ setWrapBasedOnCount();
+}
+
+void QQuickTumbler::keyPressEvent(QKeyEvent *event)
+{
QQuickControl::keyPressEvent(event);
- if (event->isAutoRepeat())
+ Q_D(QQuickTumbler);
+ if (event->isAutoRepeat() || !d->view)
return;
if (event->key() == Qt::Key_Up) {
- QMetaObject::invokeMethod(d->contentItem, "decrementCurrentIndex");
+ QMetaObject::invokeMethod(d->view, "decrementCurrentIndex");
} else if (event->key() == Qt::Key_Down) {
- QMetaObject::invokeMethod(d->contentItem, "incrementCurrentIndex");
+ QMetaObject::invokeMethod(d->view, "incrementCurrentIndex");
+ }
+}
+
+void QQuickTumbler::updatePolish()
+{
+ Q_D(QQuickTumbler);
+ if (d->pendingCurrentIndex != -1) {
+ // If the count is still 0, it's not going to happen.
+ if (d->count == 0) {
+ d->pendingCurrentIndex = -1;
+ return;
+ }
+
+ // If there is a pending currentIndex at this stage, it means that
+ // the view wouldn't set our currentIndex in _q_onViewCountChanged
+ // because it wasn't ready. Try one last time here.
+ setCurrentIndex(d->pendingCurrentIndex);
+
+ if (d->currentIndex != d->pendingCurrentIndex && d->currentIndex == -1) {
+ // If we *still* couldn't set it, it's probably invalid.
+ // See if we can at least enforce our rule of "non-negative currentIndex when count > 0" instead.
+ setCurrentIndex(0);
+ }
+
+ d->pendingCurrentIndex = -1;
}
}
@@ -401,13 +667,17 @@ class QQuickTumblerAttachedPrivate : public QObjectPrivate, public QQuickItemCha
{
Q_DECLARE_PUBLIC(QQuickTumblerAttached)
public:
- QQuickTumblerAttachedPrivate(QQuickItem *delegateItem) :
+ QQuickTumblerAttachedPrivate() :
tumbler(nullptr),
index(-1),
displacement(0)
{
+ }
+
+ void init(QQuickItem *delegateItem)
+ {
if (!delegateItem->parentItem()) {
- qWarning() << "Tumbler: attached properties must be accessed from within a delegate item that has a parent";
+ qWarning() << "Tumbler: attached properties must be accessed through a delegate item that has a parent";
return;
}
@@ -418,34 +688,29 @@ public:
}
index = indexContextProperty.toInt();
- const ContentItemType contentItemType = contentItemTypeFromDelegate(delegateItem);
- if (contentItemType == UnsupportedContentItemType)
- return;
- // ListView has an "additional" content item.
- tumbler = qobject_cast<QQuickTumbler* >(contentItemType == PathViewContentItem
- ? delegateItem->parentItem()->parentItem() : delegateItem->parentItem()->parentItem()->parentItem());
- Q_ASSERT(tumbler);
- }
-
- ~QQuickTumblerAttachedPrivate() {
+ QQuickItem *parentItem = delegateItem;
+ while ((parentItem = parentItem->parentItem())) {
+ if ((tumbler = qobject_cast<QQuickTumbler*>(parentItem)))
+ break;
+ }
}
- void itemGeometryChanged(QQuickItem *item, const QRectF &newGeometry, const QRectF &oldGeometry) override;
+ void itemGeometryChanged(QQuickItem *item, QQuickGeometryChange change, const QRectF &diff) override;
void itemChildAdded(QQuickItem *, QQuickItem *) override;
void itemChildRemoved(QQuickItem *, QQuickItem *) override;
void _q_calculateDisplacement();
// The Tumbler that contains the delegate. Required to calculated the displacement.
- QQuickTumbler *tumbler;
+ QPointer<QQuickTumbler> tumbler;
// The index of the delegate. Used to calculate the displacement.
int index;
// The displacement for our delegate.
qreal displacement;
};
-void QQuickTumblerAttachedPrivate::itemGeometryChanged(QQuickItem *, const QRectF &, const QRectF &)
+void QQuickTumblerAttachedPrivate::itemGeometryChanged(QQuickItem *, QQuickGeometryChange, const QRectF &)
{
_q_calculateDisplacement();
}
@@ -476,32 +741,37 @@ void QQuickTumblerAttachedPrivate::_q_calculateDisplacement()
const int previousDisplacement = displacement;
displacement = 0;
- const int count = tumbler->count();
- // This can happen in tests, so it may happen in normal usage too.
- if (count == 0)
+ // Can happen if the attached properties are accessed on the wrong type of item or the tumbler was destroyed.
+ if (!tumbler)
return;
- ContentItemType contentType = contentItemType(tumbler->contentItem());
- if (contentType == UnsupportedContentItemType)
+ // Can happen if there is no ListView or PathView within the contentItem.
+ QQuickTumblerPrivate *tumblerPrivate = QQuickTumblerPrivate::get(tumbler);
+ if (!tumblerPrivate->viewContentItem)
return;
- qreal offset = 0;
+ // The attached property gets created before our count is updated, so just cheat here
+ // to avoid having to listen to count changes.
+ const int count = tumblerPrivate->view->property("count").toInt();
+ // This can happen in tests, so it may happen in normal usage too.
+ if (count == 0)
+ return;
- if (contentType == PathViewContentItem) {
- offset = tumbler->contentItem()->property("offset").toReal();
+ if (tumblerPrivate->viewContentItemType == QQuickTumblerPrivate::PathViewContentItem) {
+ const qreal offset = tumblerPrivate->view->property("offset").toReal();
displacement = count > 1 ? count - index - offset : 0;
// Don't add 1 if count <= visibleItemCount
const int visibleItems = tumbler->visibleItemCount();
- int halfVisibleItems = visibleItems / 2 + (visibleItems < count ? 1 : 0);
+ const int halfVisibleItems = visibleItems / 2 + (visibleItems < count ? 1 : 0);
if (displacement > halfVisibleItems)
displacement -= count;
else if (displacement < -halfVisibleItems)
displacement += count;
} else {
- const qreal contentY = tumbler->contentItem()->property("contentY").toReal();
+ const qreal contentY = tumblerPrivate->view->property("contentY").toReal();
const qreal delegateH = delegateHeight(tumbler);
- const qreal preferredHighlightBegin = tumbler->contentItem()->property("preferredHighlightBegin").toReal();
+ const qreal preferredHighlightBegin = tumblerPrivate->view->property("preferredHighlightBegin").toReal();
// Tumbler's displacement goes from negative at the top to positive towards the bottom, so we must switch this around.
const qreal reverseDisplacement = (contentY + preferredHighlightBegin) / delegateH;
displacement = reverseDisplacement - index;
@@ -512,19 +782,34 @@ void QQuickTumblerAttachedPrivate::_q_calculateDisplacement()
emit q->displacementChanged();
}
-QQuickTumblerAttached::QQuickTumblerAttached(QQuickItem *delegateItem) :
- QObject(*(new QQuickTumblerAttachedPrivate(delegateItem)), delegateItem)
+QQuickTumblerAttached::QQuickTumblerAttached(QObject *parent) :
+ QObject(*(new QQuickTumblerAttachedPrivate), parent)
{
Q_D(QQuickTumblerAttached);
+ QQuickItem *delegateItem = qobject_cast<QQuickItem *>(parent);
+ if (delegateItem)
+ d->init(delegateItem);
+ else if (parent)
+ qmlInfo(parent) << "Tumbler: attached properties of Tumbler must be accessed through a delegate item";
+
if (d->tumbler) {
- QQuickItem *rootContentItem = d->tumbler->contentItem();
- const ContentItemType contentType = contentItemType(rootContentItem);
- QQuickItemPrivate *p = QQuickItemPrivate::get(actualContentItem(rootContentItem, contentType));
+ // When the Tumbler is completed, wrapChanged() is emitted to let QQuickTumblerView
+ // know that it can create the view. The view itself might instantiate delegates
+ // that use attached properties. At this point, setupViewData() hasn't been called yet
+ // (it's called on the next line in componentComplete()), so we call it here so that
+ // we have access to the view.
+ QQuickTumblerPrivate *tumblerPrivate = QQuickTumblerPrivate::get(d->tumbler);
+ tumblerPrivate->setupViewData(tumblerPrivate->contentItem);
+
+ if (!tumblerPrivate->viewContentItem)
+ return;
+
+ QQuickItemPrivate *p = QQuickItemPrivate::get(tumblerPrivate->viewContentItem);
p->addItemChangeListener(d, QQuickItemPrivate::Geometry | QQuickItemPrivate::Children);
- const char *contentItemSignal = contentType == PathViewContentItem
+ const char *contentItemSignal = tumblerPrivate->viewContentItemType == QQuickTumblerPrivate::PathViewContentItem
? SIGNAL(offsetChanged()) : SIGNAL(contentYChanged());
- connect(d->tumbler->contentItem(), contentItemSignal, this, SLOT(_q_calculateDisplacement()));
+ connect(tumblerPrivate->view, contentItemSignal, this, SLOT(_q_calculateDisplacement()));
d->_q_calculateDisplacement();
}
diff --git a/src/quicktemplates2/qquicktumbler_p.h b/src/quicktemplates2/qquicktumbler_p.h
index e28102e4..1c8cfa18 100644
--- a/src/quicktemplates2/qquicktumbler_p.h
+++ b/src/quicktemplates2/qquicktumbler_p.h
@@ -66,6 +66,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTumbler : public QQuickControl
Q_PROPERTY(QQuickItem *currentItem READ currentItem NOTIFY currentItemChanged FINAL)
Q_PROPERTY(QQmlComponent *delegate READ delegate WRITE setDelegate NOTIFY delegateChanged FINAL)
Q_PROPERTY(int visibleItemCount READ visibleItemCount WRITE setVisibleItemCount NOTIFY visibleItemCountChanged FINAL)
+ Q_PROPERTY(bool wrap READ wrap WRITE setWrap RESET resetWrap NOTIFY wrapChanged FINAL REVISION 1)
public:
explicit QQuickTumbler(QQuickItem *parent = nullptr);
@@ -86,6 +87,10 @@ public:
int visibleItemCount() const;
void setVisibleItemCount(int visibleItemCount);
+ bool wrap() const;
+ void setWrap(bool wrap);
+ void resetWrap();
+
static QQuickTumblerAttached *qmlAttachedProperties(QObject *object);
Q_SIGNALS:
@@ -95,12 +100,14 @@ Q_SIGNALS:
void currentItemChanged();
void delegateChanged();
void visibleItemCountChanged();
+ Q_REVISION(1) void wrapChanged();
protected:
void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
void componentComplete() override;
void contentItemChange(QQuickItem *newItem, QQuickItem *oldItem) override;
void keyPressEvent(QKeyEvent *event) override;
+ void updatePolish() override;
private:
Q_DISABLE_COPY(QQuickTumbler)
@@ -108,6 +115,8 @@ private:
Q_PRIVATE_SLOT(d_func(), void _q_updateItemWidths())
Q_PRIVATE_SLOT(d_func(), void _q_updateItemHeights())
+ Q_PRIVATE_SLOT(d_func(), void _q_onViewCurrentIndexChanged())
+ Q_PRIVATE_SLOT(d_func(), void _q_onViewCountChanged())
};
class QQuickTumblerAttachedPrivate;
@@ -119,7 +128,7 @@ class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTumblerAttached : public QObject
Q_PROPERTY(qreal displacement READ displacement NOTIFY displacementChanged FINAL)
public:
- explicit QQuickTumblerAttached(QQuickItem *delegateItem);
+ explicit QQuickTumblerAttached(QObject *parent = nullptr);
~QQuickTumblerAttached();
QQuickTumbler *tumbler() const;
diff --git a/src/quicktemplates2/qquicktumbler_p_p.h b/src/quicktemplates2/qquicktumbler_p_p.h
new file mode 100644
index 00000000..daced3a3
--- /dev/null
+++ b/src/quicktemplates2/qquicktumbler_p_p.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Templates 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKTUMBLER_P_P_H
+#define QQUICKTUMBLER_P_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtQuick/private/qquickitemchangelistener_p.h>
+#include <QtQuickTemplates2/private/qquickcontrol_p_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickTumbler;
+
+class Q_QUICKTEMPLATES2_PRIVATE_EXPORT QQuickTumblerPrivate : public QQuickControlPrivate, public QQuickItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QQuickTumbler)
+
+public:
+ QQuickTumblerPrivate();
+ ~QQuickTumblerPrivate();
+
+ enum ContentItemType {
+ UnsupportedContentItemType,
+ PathViewContentItem,
+ ListViewContentItem
+ };
+
+ QQuickItem *determineViewType(QQuickItem *contentItem);
+ void resetViewData();
+ QList<QQuickItem *> viewContentItemChildItems() const;
+
+ static QQuickTumblerPrivate *get(QQuickTumbler *tumbler);
+
+ QVariant model;
+ QQmlComponent *delegate;
+ int visibleItemCount;
+ bool wrap;
+ bool explicitWrap;
+ bool ignoreWrapChanges;
+ QQuickItem *view;
+ QQuickItem *viewContentItem;
+ ContentItemType viewContentItemType;
+ int currentIndex;
+ int pendingCurrentIndex;
+ bool ignoreCurrentIndexChanges;
+ int count;
+
+ void _q_updateItemHeights();
+ void _q_updateItemWidths();
+ void _q_onViewCurrentIndexChanged();
+ void _q_onViewCountChanged();
+
+ void disconnectFromView();
+ void setupViewData(QQuickItem *newControlContentItem);
+ void syncCurrentIndex();
+
+ void setCount(int newCount);
+ void setWrapBasedOnCount();
+ void setWrap(bool shouldWrap, bool isExplicit);
+ void lockWrap();
+ void unlockWrap();
+
+ void itemChildAdded(QQuickItem *, QQuickItem *) override;
+ void itemChildRemoved(QQuickItem *, QQuickItem *) override;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKTUMBLER_P_P_H
diff --git a/src/quicktemplates2/quicktemplates2.pri b/src/quicktemplates2/quicktemplates2.pri
index 173112d3..f5e95aea 100644
--- a/src/quicktemplates2/quicktemplates2.pri
+++ b/src/quicktemplates2/quicktemplates2.pri
@@ -15,6 +15,10 @@ HEADERS += \
$$PWD/qquickcontrol_p.h \
$$PWD/qquickcontrol_p_p.h \
$$PWD/qquickdial_p.h \
+ $$PWD/qquickdialog_p.h \
+ $$PWD/qquickdialog_p_p.h \
+ $$PWD/qquickdialogbuttonbox_p.h \
+ $$PWD/qquickdialogbuttonbox_p_p.h \
$$PWD/qquickdrawer_p.h \
$$PWD/qquickframe_p.h \
$$PWD/qquickframe_p_p.h \
@@ -26,9 +30,11 @@ HEADERS += \
$$PWD/qquickmenu_p.h \
$$PWD/qquickmenu_p_p.h \
$$PWD/qquickmenuitem_p.h \
+ $$PWD/qquickmenuseparator_p.h \
$$PWD/qquickoverlay_p.h \
$$PWD/qquickpage_p.h \
$$PWD/qquickpageindicator_p.h \
+ $$PWD/qquickpagelayout_p_p.h \
$$PWD/qquickpane_p.h \
$$PWD/qquickpane_p_p.h \
$$PWD/qquickpopup_p.h \
@@ -56,8 +62,10 @@ HEADERS += \
$$PWD/qquicktextfield_p_p.h \
$$PWD/qquicktoolbar_p.h \
$$PWD/qquicktoolbutton_p.h \
+ $$PWD/qquicktoolseparator_p.h \
$$PWD/qquicktooltip_p.h \
$$PWD/qquicktumbler_p.h \
+ $$PWD/qquicktumbler_p_p.h \
$$PWD/qquickvelocitycalculator_p_p.h
SOURCES += \
@@ -72,6 +80,8 @@ SOURCES += \
$$PWD/qquickcontainer.cpp \
$$PWD/qquickcontrol.cpp \
$$PWD/qquickdial.cpp \
+ $$PWD/qquickdialog.cpp \
+ $$PWD/qquickdialogbuttonbox.cpp \
$$PWD/qquickdrawer.cpp \
$$PWD/qquickframe.cpp \
$$PWD/qquickgroupbox.cpp \
@@ -79,9 +89,11 @@ SOURCES += \
$$PWD/qquicklabel.cpp \
$$PWD/qquickmenu.cpp \
$$PWD/qquickmenuitem.cpp \
+ $$PWD/qquickmenuseparator.cpp \
$$PWD/qquickoverlay.cpp \
$$PWD/qquickpage.cpp \
$$PWD/qquickpageindicator.cpp \
+ $$PWD/qquickpagelayout.cpp \
$$PWD/qquickpane.cpp \
$$PWD/qquickpopup.cpp \
$$PWD/qquickpresshandler.cpp \
@@ -105,6 +117,7 @@ SOURCES += \
$$PWD/qquicktextfield.cpp \
$$PWD/qquicktoolbar.cpp \
$$PWD/qquicktoolbutton.cpp \
+ $$PWD/qquicktoolseparator.cpp \
$$PWD/qquicktooltip.cpp \
$$PWD/qquicktumbler.cpp \
$$PWD/qquickvelocitycalculator.cpp