aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/imports/controls/qtquickcontrols2plugin.cpp2
-rw-r--r--src/quickcontrols2/qquickdisplaylayout.cpp412
-rw-r--r--src/quickcontrols2/qquickdisplaylayout_p.h138
-rw-r--r--src/quickcontrols2/qquickdisplaylayout_p_p.h90
-rw-r--r--src/quickcontrols2/quickcontrols2.pri3
-rw-r--r--tests/auto/qquickdisplaylayout/data/layout.qml67
-rw-r--r--tests/auto/qquickdisplaylayout/qquickdisplaylayout.pro13
-rw-r--r--tests/auto/qquickdisplaylayout/tst_qquickdisplaylayout.cpp232
8 files changed, 957 insertions, 0 deletions
diff --git a/src/imports/controls/qtquickcontrols2plugin.cpp b/src/imports/controls/qtquickcontrols2plugin.cpp
index 2cd97daa..3a131511 100644
--- a/src/imports/controls/qtquickcontrols2plugin.cpp
+++ b/src/imports/controls/qtquickcontrols2plugin.cpp
@@ -39,6 +39,7 @@
#include <QtQuickControls2/private/qquickcolor_p.h>
#include <QtQuickControls2/private/qquickiconimage_p.h>
#include <QtQuickControls2/private/qquickplaceholdertext_p.h>
+#include <QtQuickControls2/private/qquickdisplaylayout_p.h>
#include <QtQuickControls2/private/qquickstyle_p.h>
#include <QtQuickControls2/private/qquickstyleplugin_p.h>
#include <QtQuickControls2/private/qquickstyleselector_p.h>
@@ -193,6 +194,7 @@ void QtQuickControls2Plugin::initializeEngine(QQmlEngine *engine, const char *ur
qmlRegisterType<QQuickIconImage>(import, 2, 3, "IconImage");
qmlRegisterSingletonType<QQuickColor>(import, 2, 3, "Color", colorSingleton);
+ qmlRegisterType<QQuickDisplayLayout>(import, 2, 3, "DisplayLayout");
}
QT_END_NAMESPACE
diff --git a/src/quickcontrols2/qquickdisplaylayout.cpp b/src/quickcontrols2/qquickdisplaylayout.cpp
new file mode 100644
index 00000000..dba5d604
--- /dev/null
+++ b/src/quickcontrols2/qquickdisplaylayout.cpp
@@ -0,0 +1,412 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qquickdisplaylayout_p.h"
+#include "qquickdisplaylayout_p_p.h"
+
+#include <QtQuick/private/qquickitem_p.h>
+
+QT_BEGIN_NAMESPACE
+
+QQuickDisplayLayoutPrivate::QQuickDisplayLayoutPrivate()
+ : icon(nullptr),
+ text(nullptr),
+ display(QQuickDisplayLayout::TextBesideIcon),
+ spacing(0),
+ mirrored(false),
+ topPadding(0),
+ leftPadding(0),
+ rightPadding(0),
+ bottomPadding(0)
+{
+}
+
+void QQuickDisplayLayoutPrivate::updateImplicitSize()
+{
+ Q_Q(QQuickDisplayLayout);
+ if (!q->isComponentComplete())
+ return;
+
+ const bool showIcon = icon && display != QQuickDisplayLayout::TextOnly;
+ const bool showText = text && display != QQuickDisplayLayout::IconOnly;
+ const qreal horizontalPadding = leftPadding + rightPadding;
+ const qreal verticalPadding = topPadding + bottomPadding;
+ const qreal iconImplicitWidth = showIcon ? icon->implicitWidth() : 0;
+ const qreal iconImplicitHeight = showIcon ? icon->implicitHeight() : 0;
+ const qreal textImplicitWidth = showText ? text->implicitWidth() : 0;
+ const qreal textImplicitHeight = showText ? text->implicitHeight() : 0;
+ const qreal effectiveSpacing = showText && showIcon ? spacing : 0;
+ const qreal implicitWidth = iconImplicitWidth + textImplicitWidth + effectiveSpacing + horizontalPadding;
+ const qreal implicitHeight = qMax(iconImplicitHeight, textImplicitHeight) + verticalPadding;
+ q->setImplicitSize(implicitWidth, implicitHeight);
+}
+
+void QQuickDisplayLayoutPrivate::layout()
+{
+ Q_Q(QQuickDisplayLayout);
+ if (!q->isComponentComplete())
+ return;
+
+ const qreal horizontalPadding = leftPadding + rightPadding;
+ const qreal verticalPadding = topPadding + bottomPadding;
+ const qreal w = q->width();
+ const qreal h = q->height();
+ const qreal availableWidth = w - horizontalPadding;
+ const qreal availableHeight = h - verticalPadding;
+ const qreal horizontalCenter = w / 2;
+ const qreal verticalCenter = h / 2;
+
+ switch (display) {
+ case QQuickDisplayLayout::IconOnly:
+ if (icon) {
+ icon->setWidth(qMin(icon->implicitWidth(), availableWidth));
+ icon->setHeight(qMin(icon->implicitHeight(), availableHeight));
+ icon->setX(horizontalCenter - icon->width() / 2);
+ icon->setY(verticalCenter - icon->height() / 2);
+ icon->setVisible(true);
+ }
+ if (text)
+ text->setVisible(false);
+ break;
+ case QQuickDisplayLayout::TextOnly:
+ if (text) {
+ text->setWidth(qMin(text->implicitWidth(), availableWidth));
+ text->setHeight(qMin(text->implicitHeight(), availableHeight));
+ text->setX(horizontalCenter - text->width() / 2);
+ text->setY(verticalCenter - text->height() / 2);
+ text->setVisible(true);
+ }
+ if (icon)
+ icon->setVisible(false);
+ break;
+ case QQuickDisplayLayout::TextBesideIcon:
+ default:
+ // Work out the sizes first, as the positions depend on them.
+ qreal iconWidth = 0;
+ qreal textWidth = 0;
+ if (icon) {
+ icon->setWidth(qMin(icon->implicitWidth(), availableWidth));
+ icon->setHeight(qMin(icon->implicitHeight(), availableHeight));
+ iconWidth = icon->width();
+ }
+ if (text) {
+ text->setWidth(qMin(text->implicitWidth(), availableWidth - iconWidth - spacing));
+ text->setHeight(qMin(text->implicitHeight(), availableHeight));
+ textWidth = text->width();
+ }
+
+ const qreal combinedWidth = iconWidth + spacing + textWidth;
+ const qreal contentX = horizontalCenter - combinedWidth / 2;
+ if (icon) {
+ icon->setX(mirrored ? contentX + combinedWidth - iconWidth : contentX);
+ icon->setY(verticalCenter - icon->height() / 2);
+ icon->setVisible(true);
+ }
+ if (text) {
+ text->setX(mirrored ? contentX : contentX + combinedWidth - text->width());
+ text->setY(verticalCenter - text->height() / 2);
+ text->setVisible(true);
+ }
+ break;
+ }
+}
+
+static const QQuickItemPrivate::ChangeTypes itemChangeTypes =
+ QQuickItemPrivate::ImplicitWidth
+ | QQuickItemPrivate::ImplicitHeight
+ | QQuickItemPrivate::Destroyed;
+
+void QQuickDisplayLayoutPrivate::watchChanges(QQuickItem *item)
+{
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ itemPrivate->addItemChangeListener(this, itemChangeTypes);
+}
+
+void QQuickDisplayLayoutPrivate::unwatchChanges(QQuickItem* item)
+{
+ QQuickItemPrivate *itemPrivate = QQuickItemPrivate::get(item);
+ itemPrivate->removeItemChangeListener(this, itemChangeTypes);
+}
+
+void QQuickDisplayLayoutPrivate::itemImplicitWidthChanged(QQuickItem *)
+{
+ updateImplicitSize();
+}
+
+void QQuickDisplayLayoutPrivate::itemImplicitHeightChanged(QQuickItem *)
+{
+ updateImplicitSize();
+}
+
+void QQuickDisplayLayoutPrivate::itemDestroyed(QQuickItem *item)
+{
+ unwatchChanges(item);
+ if (item == icon)
+ icon = nullptr;
+ else if (item == text)
+ text = nullptr;
+}
+
+QQuickDisplayLayout::QQuickDisplayLayout(QQuickItem *parent)
+ : QQuickItem(*(new QQuickDisplayLayoutPrivate), parent)
+{
+}
+
+QQuickDisplayLayout::~QQuickDisplayLayout()
+{
+ Q_D(QQuickDisplayLayout);
+ if (d->icon)
+ d->unwatchChanges(d->icon);
+ if (d->text)
+ d->unwatchChanges(d->text);
+}
+
+QQuickItem *QQuickDisplayLayout::icon() const
+{
+ Q_D(const QQuickDisplayLayout);
+ return d->icon;
+}
+
+void QQuickDisplayLayout::setIcon(QQuickItem *icon)
+{
+ Q_D(QQuickDisplayLayout);
+ if (d->icon == icon)
+ return;
+
+ if (d->icon)
+ d->unwatchChanges(d->icon);
+
+ d->icon = icon;
+ if (d->icon) {
+ d->icon->setParentItem(this);
+ d->watchChanges(d->icon);
+ }
+
+ d->updateImplicitSize();
+ d->layout();
+
+ emit iconChanged();
+}
+
+QQuickItem *QQuickDisplayLayout::text() const
+{
+ Q_D(const QQuickDisplayLayout);
+ return d->text;
+}
+
+void QQuickDisplayLayout::setText(QQuickItem *text)
+{
+ Q_D(QQuickDisplayLayout);
+ if (d->text == text)
+ return;
+
+ if (d->text)
+ d->unwatchChanges(d->text);
+
+ d->text = text;
+ if (d->text) {
+ d->text->setParentItem(this);
+ d->watchChanges(d->text);
+ }
+
+ d->updateImplicitSize();
+ d->layout();
+
+ emit textChanged();
+}
+
+QQuickDisplayLayout::Display QQuickDisplayLayout::display() const
+{
+ Q_D(const QQuickDisplayLayout);
+ return d->display;
+}
+
+void QQuickDisplayLayout::setDisplay(Display display)
+{
+ Q_D(QQuickDisplayLayout);
+ if (d->display == display)
+ return;
+
+ d->display = display;
+ d->updateImplicitSize();
+ d->layout();
+ emit displayChanged();
+}
+
+qreal QQuickDisplayLayout::spacing() const
+{
+ Q_D(const QQuickDisplayLayout);
+ return d->spacing;
+}
+
+void QQuickDisplayLayout::setSpacing(qreal spacing)
+{
+ Q_D(QQuickDisplayLayout);
+ if (qFuzzyCompare(d->spacing, spacing))
+ return;
+
+ d->spacing = spacing;
+ d->updateImplicitSize();
+ d->layout();
+ emit spacingChanged();
+}
+
+bool QQuickDisplayLayout::isMirrored() const
+{
+ Q_D(const QQuickDisplayLayout);
+ return d->mirrored;
+}
+
+void QQuickDisplayLayout::setMirrored(bool mirrored)
+{
+ Q_D(QQuickDisplayLayout);
+ if (d->mirrored == mirrored)
+ return;
+
+ d->mirrored = mirrored;
+ d->updateImplicitSize();
+ d->layout();
+ emit mirroredChanged();
+}
+
+qreal QQuickDisplayLayout::topPadding() const
+{
+ Q_D(const QQuickDisplayLayout);
+ return d->topPadding;
+}
+
+void QQuickDisplayLayout::setTopPadding(qreal padding)
+{
+ Q_D(QQuickDisplayLayout);
+ if (qFuzzyCompare(d->topPadding, padding))
+ return;
+
+ d->topPadding = padding;
+ d->updateImplicitSize();
+ d->layout();
+ emit topPaddingChanged();
+}
+
+void QQuickDisplayLayout::resetTopPadding()
+{
+ setTopPadding(0);
+}
+
+qreal QQuickDisplayLayout::leftPadding() const
+{
+ Q_D(const QQuickDisplayLayout);
+ return d->leftPadding;
+}
+
+void QQuickDisplayLayout::setLeftPadding(qreal padding)
+{
+ Q_D(QQuickDisplayLayout);
+ if (qFuzzyCompare(d->leftPadding, padding))
+ return;
+
+ d->leftPadding = padding;
+ d->updateImplicitSize();
+ d->layout();
+ emit leftPaddingChanged();
+}
+
+void QQuickDisplayLayout::resetLeftPadding()
+{
+ setLeftPadding(0);
+}
+
+qreal QQuickDisplayLayout::rightPadding() const
+{
+ Q_D(const QQuickDisplayLayout);
+ return d->rightPadding;
+}
+
+void QQuickDisplayLayout::setRightPadding(qreal padding)
+{
+ Q_D(QQuickDisplayLayout);
+ if (qFuzzyCompare(d->rightPadding, padding))
+ return;
+
+ d->rightPadding = padding;
+ d->updateImplicitSize();
+ d->layout();
+ emit rightPaddingChanged();
+}
+
+void QQuickDisplayLayout::resetRightPadding()
+{
+ setRightPadding(0);
+}
+
+qreal QQuickDisplayLayout::bottomPadding() const
+{
+ Q_D(const QQuickDisplayLayout);
+ return d->bottomPadding;
+}
+
+void QQuickDisplayLayout::setBottomPadding(qreal padding)
+{
+ Q_D(QQuickDisplayLayout);
+ if (qFuzzyCompare(d->bottomPadding, padding))
+ return;
+
+ d->bottomPadding = padding;
+ d->updateImplicitSize();
+ d->layout();
+ emit bottomPaddingChanged();
+}
+
+void QQuickDisplayLayout::resetBottomPadding()
+{
+ setBottomPadding(0);
+}
+
+void QQuickDisplayLayout::componentComplete()
+{
+ Q_D(QQuickDisplayLayout);
+ QQuickItem::componentComplete();
+ d->updateImplicitSize();
+ d->layout();
+}
+
+void QQuickDisplayLayout::geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry)
+{
+ Q_D(QQuickDisplayLayout);
+ QQuickItem::geometryChanged(newGeometry, oldGeometry);
+ d->layout();
+}
+
+QT_END_NAMESPACE
diff --git a/src/quickcontrols2/qquickdisplaylayout_p.h b/src/quickcontrols2/qquickdisplaylayout_p.h
new file mode 100644
index 00000000..dde0aaf8
--- /dev/null
+++ b/src/quickcontrols2/qquickdisplaylayout_p.h
@@ -0,0 +1,138 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDISPLAYLAYOUT_P_H
+#define QQUICKDISPLAYLAYOUT_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/qquickitem.h>
+#include <QtQuickControls2/private/qtquickcontrols2global_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickDisplayLayoutPrivate;
+
+class Q_QUICKCONTROLS2_PRIVATE_EXPORT QQuickDisplayLayout : public QQuickItem
+{
+ Q_OBJECT
+ Q_PROPERTY(QQuickItem *icon READ icon WRITE setIcon NOTIFY iconChanged FINAL)
+ Q_PROPERTY(QQuickItem *text READ text WRITE setText NOTIFY textChanged FINAL)
+ Q_PROPERTY(Display display READ display WRITE setDisplay NOTIFY displayChanged FINAL)
+ Q_PROPERTY(qreal spacing READ spacing WRITE setSpacing NOTIFY spacingChanged)
+ Q_PROPERTY(bool mirrored READ isMirrored WRITE setMirrored NOTIFY mirroredChanged)
+ Q_PROPERTY(qreal topPadding READ topPadding WRITE setTopPadding RESET resetTopPadding NOTIFY topPaddingChanged)
+ Q_PROPERTY(qreal leftPadding READ leftPadding WRITE setLeftPadding RESET resetLeftPadding NOTIFY leftPaddingChanged)
+ Q_PROPERTY(qreal rightPadding READ rightPadding WRITE setRightPadding RESET resetRightPadding NOTIFY rightPaddingChanged)
+ Q_PROPERTY(qreal bottomPadding READ bottomPadding WRITE setBottomPadding RESET resetBottomPadding NOTIFY bottomPaddingChanged)
+
+public:
+ enum Display {
+ IconOnly,
+ TextOnly,
+ TextBesideIcon,
+ TextUnderIcon // unused, but reserved for future use
+ };
+ Q_ENUM(Display)
+
+ explicit QQuickDisplayLayout(QQuickItem *parent = nullptr);
+ ~QQuickDisplayLayout();
+
+ QQuickItem *icon() const;
+ void setIcon(QQuickItem *icon);
+
+ QQuickItem *text() const;
+ void setText(QQuickItem *text);
+
+ Display display() const;
+ void setDisplay(Display display);
+
+ qreal spacing() const;
+ void setSpacing(qreal spacing);
+
+ bool isMirrored() const;
+ void setMirrored(bool mirrored);
+
+ qreal topPadding() const;
+ void setTopPadding(qreal padding);
+ void resetTopPadding();
+
+ qreal leftPadding() const;
+ void setLeftPadding(qreal padding);
+ void resetLeftPadding();
+
+ qreal rightPadding() const;
+ void setRightPadding(qreal padding);
+ void resetRightPadding();
+
+ qreal bottomPadding() const;
+ void setBottomPadding(qreal padding);
+ void resetBottomPadding();
+
+Q_SIGNALS:
+ void iconChanged();
+ void textChanged();
+ void displayChanged();
+ void spacingChanged();
+ void mirroredChanged();
+ void topPaddingChanged();
+ void leftPaddingChanged();
+ void rightPaddingChanged();
+ void bottomPaddingChanged();
+
+protected:
+ void componentComplete() override;
+ void geometryChanged(const QRectF &newGeometry, const QRectF &oldGeometry) override;
+
+private:
+ Q_DISABLE_COPY(QQuickDisplayLayout)
+ Q_DECLARE_PRIVATE(QQuickDisplayLayout)
+};
+
+QT_END_NAMESPACE
+
+QML_DECLARE_TYPE(QQuickDisplayLayout)
+
+#endif // QQUICKDISPLAYLAYOUT_P_H
diff --git a/src/quickcontrols2/qquickdisplaylayout_p_p.h b/src/quickcontrols2/qquickdisplaylayout_p_p.h
new file mode 100644
index 00000000..1397b93a
--- /dev/null
+++ b/src/quickcontrols2/qquickdisplaylayout_p_p.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
+**
+** This file is part of the Qt Quick Controls 2 module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL3$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 3 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPLv3 included in the
+** packaging of this file. Please review the following information to
+** ensure the GNU Lesser General Public License version 3 requirements
+** will be met: https://www.gnu.org/licenses/lgpl.html.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 2.0 or later as published by the Free
+** Software Foundation and appearing in the file LICENSE.GPL included in
+** the packaging of this file. Please review the following information to
+** ensure the GNU General Public License version 2.0 requirements will be
+** met: http://www.gnu.org/licenses/gpl-2.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QQUICKDISPLAYLAYOUT_P_P_H
+#define QQUICKDISPLAYLAYOUT_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/qquickitem_p.h>
+#include <QtQuickControls2/private/qtquickcontrols2global_p.h>
+#include <QtQuickControls2/private/qquickdisplaylayout_p.h>
+
+QT_BEGIN_NAMESPACE
+
+class QQuickDisplayLayoutPrivate : public QQuickItemPrivate, public QQuickItemChangeListener
+{
+ Q_DECLARE_PUBLIC(QQuickDisplayLayout)
+
+public:
+ explicit QQuickDisplayLayoutPrivate();
+
+ void updateImplicitSize();
+ void layout();
+
+ void watchChanges(QQuickItem *item);
+ void unwatchChanges(QQuickItem *item);
+ void setPositioningDirty();
+
+ bool isLeftToRight() const;
+
+ void itemImplicitWidthChanged(QQuickItem *) override;
+ void itemImplicitHeightChanged(QQuickItem *) override;
+ void itemDestroyed(QQuickItem *item) override;
+
+ QQuickItem *icon;
+ QQuickItem *text;
+ QQuickDisplayLayout::Display display;
+ qreal spacing;
+ bool mirrored;
+ qreal topPadding;
+ qreal leftPadding;
+ qreal rightPadding;
+ qreal bottomPadding;
+};
+
+QT_END_NAMESPACE
+
+#endif // QQUICKDISPLAYLAYOUT_P_P_H
diff --git a/src/quickcontrols2/quickcontrols2.pri b/src/quickcontrols2/quickcontrols2.pri
index ed01660e..83ffb687 100644
--- a/src/quickcontrols2/quickcontrols2.pri
+++ b/src/quickcontrols2/quickcontrols2.pri
@@ -2,6 +2,8 @@ HEADERS += \
$$PWD/qquickanimatednode_p.h \
$$PWD/qquickcolor_p.h \
$$PWD/qquickcolorimageprovider_p.h \
+ $$PWD/qquickdisplaylayout_p.h \
+ $$PWD/qquickdisplaylayout_p_p.h \
$$PWD/qquickiconimage_p.h \
$$PWD/qquickiconimage_p_p.h \
$$PWD/qquickplaceholdertext_p.h \
@@ -18,6 +20,7 @@ SOURCES += \
$$PWD/qquickanimatednode.cpp \
$$PWD/qquickcolor.cpp \
$$PWD/qquickcolorimageprovider.cpp \
+ $$PWD/qquickdisplaylayout.cpp \
$$PWD/qquickiconimage.cpp \
$$PWD/qquickplaceholdertext.cpp \
$$PWD/qquickproxytheme.cpp \
diff --git a/tests/auto/qquickdisplaylayout/data/layout.qml b/tests/auto/qquickdisplaylayout/data/layout.qml
new file mode 100644
index 00000000..4bfadf8e
--- /dev/null
+++ b/tests/auto/qquickdisplaylayout/data/layout.qml
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+import QtQuick 2.9
+import QtQuick.Controls 2.3
+import QtQuick.Controls.impl 2.3
+
+Item {
+ width: 200
+ height: 200
+
+ DisplayLayout {
+ icon: Image {
+ source: "qrc:/qt-project.org/imports/QtQuick/Controls.2/images/check.png"
+ }
+ text: Text {
+ text: "Some text"
+ }
+ }
+}
diff --git a/tests/auto/qquickdisplaylayout/qquickdisplaylayout.pro b/tests/auto/qquickdisplaylayout/qquickdisplaylayout.pro
new file mode 100644
index 00000000..6b2a1ae4
--- /dev/null
+++ b/tests/auto/qquickdisplaylayout/qquickdisplaylayout.pro
@@ -0,0 +1,13 @@
+CONFIG += testcase
+macos:CONFIG -= app_bundle
+TARGET = tst_qquickdisplaylayout
+
+QT += core gui qml quick testlib
+QT_PRIVATE += quick-private quickcontrols2-private
+
+include (../shared/util.pri)
+
+SOURCES += tst_qquickdisplaylayout.cpp
+
+TESTDATA += \
+ $$PWD/data/*.qml
diff --git a/tests/auto/qquickdisplaylayout/tst_qquickdisplaylayout.cpp b/tests/auto/qquickdisplaylayout/tst_qquickdisplaylayout.cpp
new file mode 100644
index 00000000..9de21145
--- /dev/null
+++ b/tests/auto/qquickdisplaylayout/tst_qquickdisplaylayout.cpp
@@ -0,0 +1,232 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtCore/qvector.h>
+
+#include <qtest.h>
+#include <QtTest/qsignalspy.h>
+
+#include <QtQuick/qquickitem.h>
+#include <QtQuick/qquickview.h>
+
+#include <QtQuickControls2/private/qquickdisplaylayout_p.h>
+
+#include "../shared/util.h"
+#include "../shared/visualtestutil.h"
+
+using namespace QQuickVisualTestUtil;
+
+class tst_qquickdisplaylayout : public QQmlDataTest
+{
+ Q_OBJECT
+public:
+ tst_qquickdisplaylayout();
+
+private slots:
+ void display_data();
+ void display();
+ void explicitLayoutSize();
+};
+
+tst_qquickdisplaylayout::tst_qquickdisplaylayout()
+{
+}
+
+void tst_qquickdisplaylayout::display_data()
+{
+ QTest::addColumn<QVector<QQuickDisplayLayout::Display> >("displayTypes");
+ QTest::addColumn<bool>("mirrored");
+ QTest::addColumn<qreal>("layoutWidth");
+ QTest::addColumn<qreal>("layoutHeight");
+ QTest::addColumn<qreal>("spacing");
+
+ typedef QVector<QQuickDisplayLayout::Display> DisplayVector;
+ QQuickDisplayLayout::Display IconOnly = QQuickDisplayLayout::IconOnly;
+ QQuickDisplayLayout::Display TextOnly = QQuickDisplayLayout::TextOnly;
+ QQuickDisplayLayout::Display TextBesideIcon = QQuickDisplayLayout::TextBesideIcon;
+
+ QTest::addRow("IconOnly") << (DisplayVector() << IconOnly) << false << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextOnly") << (DisplayVector() << TextOnly) << false << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextBesideIcon") << (DisplayVector() << TextBesideIcon) << false << -1.0 << -1.0 << 10.0;
+ QTest::addRow("IconOnly, spacing=10") << (DisplayVector() << IconOnly) << false << -1.0 << -1.0 << 10.0;
+ QTest::addRow("TextOnly, spacing=10") << (DisplayVector() << TextOnly) << false << -1.0 << -1.0 << 10.0;
+ QTest::addRow("TextBesideIcon, spacing=10") << (DisplayVector() << TextBesideIcon) << false << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextBesideIcon => IconOnly => TextBesideIcon")
+ << (DisplayVector() << TextBesideIcon << IconOnly << TextBesideIcon) << false << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextBesideIcon => IconOnly => TextBesideIcon, layoutWidth=400")
+ << (DisplayVector() << TextBesideIcon << IconOnly << TextBesideIcon) << false << 400.0 << -1.0 << 0.0;
+ QTest::addRow("TextBesideIcon => TextOnly => TextBesideIcon")
+ << (DisplayVector() << TextBesideIcon << TextOnly << TextBesideIcon) << false << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextBesideIcon => TextOnly => TextBesideIcon, layoutWidth=400")
+ << (DisplayVector() << TextBesideIcon << TextOnly << TextBesideIcon) << false << 400.0 << -1.0 << 0.0;
+ QTest::addRow("IconOnly, mirrored") << (DisplayVector() << IconOnly) << true << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextOnly, mirrored") << (DisplayVector() << TextOnly) << true << -1.0 << -1.0 << 0.0;
+ QTest::addRow("TextBesideIcon, mirrored") << (DisplayVector() << TextBesideIcon) << true << -1.0 << -1.0 << 0.0;
+}
+
+void tst_qquickdisplaylayout::display()
+{
+ QFETCH(QVector<QQuickDisplayLayout::Display>, displayTypes);
+ QFETCH(bool, mirrored);
+ QFETCH(qreal, layoutWidth);
+ QFETCH(qreal, layoutHeight);
+ QFETCH(qreal, spacing);
+
+ QQuickView view(testFileUrl("layout.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QQuickItem *rootItem = view.rootObject();
+ QVERIFY(rootItem);
+
+ QQuickDisplayLayout *layout = qobject_cast<QQuickDisplayLayout*>(rootItem->childItems().first());
+ QVERIFY(layout);
+ QCOMPARE(layout->spacing(), 0.0);
+ QCOMPARE(layout->display(), QQuickDisplayLayout::TextBesideIcon);
+ QCOMPARE(layout->isMirrored(), false);
+
+ // Setting layoutWidth allows us to test the issue where the icon's
+ // width was not updated after switching between different display types.
+ if (!qFuzzyCompare(layoutWidth, -1)) {
+ layout->setWidth(layoutWidth);
+ QCOMPARE(layout->width(), layoutWidth);
+ }
+ if (!qFuzzyCompare(layoutHeight, -1)) {
+ layout->setHeight(layoutHeight);
+ QCOMPARE(layout->height(), layoutHeight);
+ }
+
+ QQuickItem *icon = layout->icon();
+ QVERIFY(icon);
+
+ QQuickItem *text = layout->text();
+ QVERIFY(text);
+
+ QSignalSpy mirroredSpy(layout, SIGNAL(mirroredChanged()));
+ bool expectChange = layout->isMirrored() != mirrored;
+ layout->setMirrored(mirrored);
+ QCOMPARE(layout->isMirrored(), mirrored);
+ QCOMPARE(mirroredSpy.count(), expectChange ? 1 : 0);
+
+ QSignalSpy spacingSpy(layout, SIGNAL(spacingChanged()));
+ expectChange = !qFuzzyCompare(layout->spacing(), spacing);
+ layout->setSpacing(spacing);
+ QCOMPARE(layout->spacing(), spacing);
+ QCOMPARE(spacingSpy.count(), expectChange ? 1 : 0);
+
+ const qreal horizontalPadding = layout->leftPadding() + layout->rightPadding();
+ const qreal verticalPadding = layout->topPadding() + layout->bottomPadding();
+
+ // Test that the icon and text are correctly positioned and sized after
+ // setting several different display types in succession.
+ for (QQuickDisplayLayout::Display displayType : qAsConst(displayTypes)) {
+ QSignalSpy displaySpy(layout, SIGNAL(displayChanged()));
+ const bool expectChange = layout->display() != displayType;
+ layout->setDisplay(displayType);
+ QCOMPARE(layout->display(), displayType);
+ QCOMPARE(displaySpy.count(), expectChange ? 1 : 0);
+
+ const qreal horizontalCenter = layout->width() / 2;
+ const qreal verticalCenter = layout->height() / 2;
+
+ switch (displayType) {
+ case QQuickDisplayLayout::IconOnly:
+ QCOMPARE(icon->x(), horizontalCenter - icon->width() / 2);
+ QCOMPARE(icon->y(), verticalCenter - icon->height() / 2);
+ QCOMPARE(icon->width(), icon->implicitWidth());
+ QCOMPARE(icon->height(), icon->implicitHeight());
+ QCOMPARE(icon->isVisible(), true);
+ QCOMPARE(text->isVisible(), false);
+ QCOMPARE(layout->implicitWidth(), icon->implicitWidth() + horizontalPadding);
+ QCOMPARE(layout->implicitHeight(), icon->implicitHeight() + verticalPadding);
+ break;
+ case QQuickDisplayLayout::TextOnly:
+ QCOMPARE(icon->isVisible(), false);
+ QCOMPARE(text->x(), horizontalCenter - text->width() / 2);
+ QCOMPARE(text->y(), verticalCenter - text->height() / 2);
+ QCOMPARE(text->width(), text->implicitWidth());
+ QCOMPARE(text->height(), text->implicitHeight());
+ QCOMPARE(text->isVisible(), true);
+ QCOMPARE(layout->implicitWidth(), text->implicitWidth() + horizontalPadding);
+ QCOMPARE(layout->implicitHeight(), text->implicitHeight() + verticalPadding);
+ break;
+ case QQuickDisplayLayout::TextBesideIcon:
+ default:
+ const qreal combinedWidth = icon->width() + layout->spacing() + text->width();
+ const qreal contentX = horizontalCenter - combinedWidth / 2;
+ QCOMPARE(icon->x(), contentX + (layout->isMirrored() ? text->width() + layout->spacing() : 0));
+ QCOMPARE(icon->y(), verticalCenter - icon->height() / 2);
+ QCOMPARE(icon->width(), icon->implicitWidth());
+ QCOMPARE(icon->height(), icon->implicitHeight());
+ QCOMPARE(icon->isVisible(), true);
+ QCOMPARE(text->x(), contentX + (layout->isMirrored() ? 0 : icon->width() + layout->spacing()));
+ QCOMPARE(text->y(), verticalCenter - text->height() / 2);
+ QCOMPARE(text->width(), text->implicitWidth());
+ QCOMPARE(text->height(), text->implicitHeight());
+ QCOMPARE(text->isVisible(), true);
+ QCOMPARE(layout->implicitWidth(), combinedWidth + horizontalPadding);
+ QCOMPARE(layout->implicitHeight(), qMax(icon->implicitHeight(), text->implicitHeight()) + verticalPadding);
+ break;
+ }
+ }
+}
+
+void tst_qquickdisplaylayout::explicitLayoutSize()
+{
+ QQuickView view(testFileUrl("layout.qml"));
+ QCOMPARE(view.status(), QQuickView::Ready);
+ view.show();
+ QVERIFY(QTest::qWaitForWindowExposed(&view));
+
+ QQuickItem *rootItem = view.rootObject();
+ QVERIFY(rootItem);
+
+ QQuickDisplayLayout *layout = qobject_cast<QQuickDisplayLayout*>(rootItem->childItems().first());
+ QVERIFY(layout);
+
+ QQuickItem *icon = layout->icon();
+ QVERIFY(icon);
+
+ QQuickItem *text = layout->text();
+ QVERIFY(text);
+
+ // Make the row larger than its implicit width, and check that
+ // the items are still positioned correctly.
+ layout->setWidth(layout->implicitWidth() + 100);
+ QCOMPARE(icon->x(), 0.0);
+ QCOMPARE(text->x(), icon->implicitWidth());
+
+ layout->setMirrored(true);
+ QCOMPARE(icon->x(), layout->width() - icon->implicitWidth());
+ QCOMPARE(text->x(), 0.0);
+}
+
+QTEST_MAIN(tst_qquickdisplaylayout)
+
+#include "tst_qquickdisplaylayout.moc"