diff options
-rw-r--r-- | src/imports/controls/qtquickcontrols2plugin.cpp | 2 | ||||
-rw-r--r-- | src/quickcontrols2/qquickdisplaylayout.cpp | 412 | ||||
-rw-r--r-- | src/quickcontrols2/qquickdisplaylayout_p.h | 138 | ||||
-rw-r--r-- | src/quickcontrols2/qquickdisplaylayout_p_p.h | 90 | ||||
-rw-r--r-- | src/quickcontrols2/quickcontrols2.pri | 3 | ||||
-rw-r--r-- | tests/auto/qquickdisplaylayout/data/layout.qml | 67 | ||||
-rw-r--r-- | tests/auto/qquickdisplaylayout/qquickdisplaylayout.pro | 13 | ||||
-rw-r--r-- | tests/auto/qquickdisplaylayout/tst_qquickdisplaylayout.cpp | 232 |
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" |