| 1 | /**************************************************************************** |
| 2 | ** |
| 3 | ** Copyright (C) 2017 The Qt Company Ltd. |
| 4 | ** Contact: https://www.qt.io/licensing/ |
| 5 | ** |
| 6 | ** This file is part of the test suite of the Qt Toolkit. |
| 7 | ** |
| 8 | ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ |
| 9 | ** Commercial License Usage |
| 10 | ** Licensees holding valid commercial Qt licenses may use this file in |
| 11 | ** accordance with the commercial license agreement provided with the |
| 12 | ** Software or, alternatively, in accordance with the terms contained in |
| 13 | ** a written agreement between you and The Qt Company. For licensing terms |
| 14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
| 15 | ** information use the contact form at https://www.qt.io/contact-us. |
| 16 | ** |
| 17 | ** GNU General Public License Usage |
| 18 | ** Alternatively, this file may be used under the terms of the GNU |
| 19 | ** General Public License version 3 as published by the Free Software |
| 20 | ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT |
| 21 | ** included in the packaging of this file. Please review the following |
| 22 | ** information to ensure the GNU General Public License requirements will |
| 23 | ** be met: https://www.gnu.org/licenses/gpl-3.0.html. |
| 24 | ** |
| 25 | ** $QT_END_LICENSE$ |
| 26 | ** |
| 27 | ****************************************************************************/ |
| 28 | |
| 29 | #include <QtCore/qvector.h> |
| 30 | |
| 31 | #include <qtest.h> |
| 32 | |
| 33 | #include <QtQuick/qquickitem.h> |
| 34 | #include <QtQuick/qquickview.h> |
| 35 | #include <QtQuick/qquickitemgrabresult.h> |
| 36 | #include <QtQuick/private/qquicktext_p.h> |
| 37 | #include <QtQuickTemplates2/private/qquickicon_p.h> |
| 38 | #include <QtQuickControls2/private/qquickiconimage_p.h> |
| 39 | #include <QtQuickControls2/private/qquickiconlabel_p.h> |
| 40 | |
| 41 | #include "../shared/util.h" |
| 42 | #include "../shared/visualtestutil.h" |
| 43 | |
| 44 | using namespace QQuickVisualTestUtil; |
| 45 | |
| 46 | class tst_qquickiconlabel : public QQmlDataTest |
| 47 | { |
| 48 | Q_OBJECT |
| 49 | public: |
| 50 | tst_qquickiconlabel(); |
| 51 | |
| 52 | private slots: |
| 53 | void display_data(); |
| 54 | void display(); |
| 55 | void spacingWithOneDelegate_data(); |
| 56 | void spacingWithOneDelegate(); |
| 57 | void emptyIconSource(); |
| 58 | void colorChanges(); |
| 59 | }; |
| 60 | |
| 61 | tst_qquickiconlabel::tst_qquickiconlabel() |
| 62 | { |
| 63 | } |
| 64 | |
| 65 | void tst_qquickiconlabel::display_data() |
| 66 | { |
| 67 | QTest::addColumn<QVector<QQuickIconLabel::Display> >(name: "displayTypes" ); |
| 68 | QTest::addColumn<bool>(name: "mirrored" ); |
| 69 | QTest::addColumn<qreal>(name: "labelWidth" ); |
| 70 | QTest::addColumn<qreal>(name: "labelHeight" ); |
| 71 | QTest::addColumn<qreal>(name: "spacing" ); |
| 72 | |
| 73 | typedef QVector<QQuickIconLabel::Display> DisplayVector; |
| 74 | QQuickIconLabel::Display IconOnly = QQuickIconLabel::IconOnly; |
| 75 | QQuickIconLabel::Display TextOnly = QQuickIconLabel::TextOnly; |
| 76 | QQuickIconLabel::Display TextUnderIcon = QQuickIconLabel::TextUnderIcon; |
| 77 | QQuickIconLabel::Display TextBesideIcon = QQuickIconLabel::TextBesideIcon; |
| 78 | |
| 79 | QTest::addRow(format: "IconOnly" ) << (DisplayVector() << IconOnly) << false << -1.0 << -1.0 << 0.0; |
| 80 | QTest::addRow(format: "TextOnly" ) << (DisplayVector() << TextOnly) << false << -1.0 << -1.0 << 0.0; |
| 81 | QTest::addRow(format: "TextUnderIcon" ) << (DisplayVector() << TextUnderIcon) << false << -1.0 << -1.0 << 10.0; |
| 82 | QTest::addRow(format: "TextBesideIcon" ) << (DisplayVector() << TextBesideIcon) << false << -1.0 << -1.0 << 10.0; |
| 83 | QTest::addRow(format: "IconOnly, spacing=10" ) << (DisplayVector() << IconOnly) << false << -1.0 << -1.0 << 10.0; |
| 84 | QTest::addRow(format: "TextOnly, spacing=10" ) << (DisplayVector() << TextOnly) << false << -1.0 << -1.0 << 10.0; |
| 85 | QTest::addRow(format: "TextUnderIcon, spacing=10" ) << (DisplayVector() << TextUnderIcon) << false << -1.0 << -1.0 << 0.0; |
| 86 | QTest::addRow(format: "TextUnderIcon => IconOnly => TextUnderIcon" ) |
| 87 | << (DisplayVector() << TextUnderIcon << IconOnly << TextUnderIcon) << false << -1.0 << -1.0 << 0.0; |
| 88 | QTest::addRow(format: "TextUnderIcon => IconOnly => TextUnderIcon, labelWidth=400" ) |
| 89 | << (DisplayVector() << TextUnderIcon << IconOnly << TextUnderIcon) << false << 400.0 << -1.0 << 0.0; |
| 90 | QTest::addRow(format: "TextUnderIcon => TextOnly => TextUnderIcon" ) |
| 91 | << (DisplayVector() << TextUnderIcon << TextOnly << TextUnderIcon) << false << -1.0 << -1.0 << 0.0; |
| 92 | QTest::addRow(format: "TextUnderIcon => TextOnly => TextUnderIcon, labelWidth=400" ) |
| 93 | << (DisplayVector() << TextUnderIcon << TextOnly << TextUnderIcon) << false << 400.0 << -1.0 << 0.0; |
| 94 | QTest::addRow(format: "TextBesideIcon, spacing=10" ) << (DisplayVector() << TextBesideIcon) << false << -1.0 << -1.0 << 0.0; |
| 95 | QTest::addRow(format: "TextBesideIcon => IconOnly => TextBesideIcon" ) |
| 96 | << (DisplayVector() << TextBesideIcon << IconOnly << TextBesideIcon) << false << -1.0 << -1.0 << 0.0; |
| 97 | QTest::addRow(format: "TextBesideIcon => IconOnly => TextBesideIcon, labelWidth=400" ) |
| 98 | << (DisplayVector() << TextBesideIcon << IconOnly << TextBesideIcon) << false << 400.0 << -1.0 << 0.0; |
| 99 | QTest::addRow(format: "TextBesideIcon => TextOnly => TextBesideIcon" ) |
| 100 | << (DisplayVector() << TextBesideIcon << TextOnly << TextBesideIcon) << false << -1.0 << -1.0 << 0.0; |
| 101 | QTest::addRow(format: "TextBesideIcon => TextOnly => TextBesideIcon, labelWidth=400" ) |
| 102 | << (DisplayVector() << TextBesideIcon << TextOnly << TextBesideIcon) << false << 400.0 << -1.0 << 0.0; |
| 103 | QTest::addRow(format: "IconOnly, mirrored" ) << (DisplayVector() << IconOnly) << true << -1.0 << -1.0 << 0.0; |
| 104 | QTest::addRow(format: "TextOnly, mirrored" ) << (DisplayVector() << TextOnly) << true << -1.0 << -1.0 << 0.0; |
| 105 | QTest::addRow(format: "TextUnderIcon, mirrored" ) << (DisplayVector() << TextUnderIcon) << true << -1.0 << -1.0 << 0.0; |
| 106 | QTest::addRow(format: "TextBesideIcon, mirrored" ) << (DisplayVector() << TextBesideIcon) << true << -1.0 << -1.0 << 0.0; |
| 107 | } |
| 108 | |
| 109 | void tst_qquickiconlabel::display() |
| 110 | { |
| 111 | QFETCH(QVector<QQuickIconLabel::Display>, displayTypes); |
| 112 | QFETCH(bool, mirrored); |
| 113 | QFETCH(qreal, labelWidth); |
| 114 | QFETCH(qreal, labelHeight); |
| 115 | QFETCH(qreal, spacing); |
| 116 | |
| 117 | QQuickView view(testFileUrl(fileName: "iconlabel.qml" )); |
| 118 | QCOMPARE(view.status(), QQuickView::Ready); |
| 119 | view.show(); |
| 120 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
| 121 | |
| 122 | QQuickItem *rootItem = view.rootObject(); |
| 123 | QVERIFY(rootItem); |
| 124 | |
| 125 | QQuickIconLabel *label = rootItem->findChild<QQuickIconLabel *>(); |
| 126 | QVERIFY(label); |
| 127 | QCOMPARE(label->spacing(), 0.0); |
| 128 | QCOMPARE(label->display(), QQuickIconLabel::TextBesideIcon); |
| 129 | QCOMPARE(label->isMirrored(), false); |
| 130 | |
| 131 | // Setting labelWidth allows us to test the issue where the icon's |
| 132 | // width was not updated after switching between different display types. |
| 133 | if (!qFuzzyCompare(p1: labelWidth, p2: -1)) { |
| 134 | label->setWidth(labelWidth); |
| 135 | QCOMPARE(label->width(), labelWidth); |
| 136 | } |
| 137 | if (!qFuzzyCompare(p1: labelHeight, p2: -1)) { |
| 138 | label->setHeight(labelHeight); |
| 139 | QCOMPARE(label->height(), labelHeight); |
| 140 | } |
| 141 | |
| 142 | label->setMirrored(mirrored); |
| 143 | QCOMPARE(label->isMirrored(), mirrored); |
| 144 | |
| 145 | label->setSpacing(spacing); |
| 146 | QCOMPARE(label->spacing(), spacing); |
| 147 | |
| 148 | const qreal horizontalPadding = label->leftPadding() + label->rightPadding(); |
| 149 | const qreal verticalPadding = label->topPadding() + label->bottomPadding(); |
| 150 | |
| 151 | // Test that the icon and text are correctly positioned and sized after |
| 152 | // setting several different display types in succession. |
| 153 | for (QQuickIconLabel::Display displayType : qAsConst(t&: displayTypes)) { |
| 154 | label->setDisplay(displayType); |
| 155 | QCOMPARE(label->display(), displayType); |
| 156 | |
| 157 | QQuickIconImage *icon = label->findChild<QQuickIconImage *>(); |
| 158 | QQuickText *text = label->findChild<QQuickText *>(); |
| 159 | |
| 160 | const qreal horizontalCenter = label->width() / 2; |
| 161 | const qreal verticalCenter = label->height() / 2; |
| 162 | |
| 163 | switch (displayType) { |
| 164 | case QQuickIconLabel::IconOnly: |
| 165 | QVERIFY(icon); |
| 166 | QVERIFY(!text); |
| 167 | QCOMPARE(icon->x(), horizontalCenter - icon->width() / 2); |
| 168 | QCOMPARE(icon->y(), verticalCenter - icon->height() / 2); |
| 169 | QCOMPARE(icon->width(), icon->implicitWidth()); |
| 170 | QCOMPARE(icon->height(), icon->implicitHeight()); |
| 171 | QCOMPARE(label->implicitWidth(), icon->implicitWidth() + horizontalPadding); |
| 172 | QCOMPARE(label->implicitHeight(), icon->implicitHeight() + verticalPadding); |
| 173 | break; |
| 174 | case QQuickIconLabel::TextOnly: |
| 175 | QVERIFY(!icon); |
| 176 | QVERIFY(text); |
| 177 | QCOMPARE(text->x(), horizontalCenter - text->width() / 2); |
| 178 | QCOMPARE(text->y(), verticalCenter - text->height() / 2); |
| 179 | QCOMPARE(text->width(), text->implicitWidth()); |
| 180 | QCOMPARE(text->height(), text->implicitHeight()); |
| 181 | QCOMPARE(label->implicitWidth(), text->implicitWidth() + horizontalPadding); |
| 182 | QCOMPARE(label->implicitHeight(), text->implicitHeight() + verticalPadding); |
| 183 | break; |
| 184 | case QQuickIconLabel::TextUnderIcon: { |
| 185 | QVERIFY(icon); |
| 186 | QVERIFY(text); |
| 187 | const qreal combinedHeight = icon->height() + label->spacing() + text->height(); |
| 188 | const qreal contentY = verticalCenter - combinedHeight / 2; |
| 189 | QCOMPARE(icon->x(), horizontalCenter - icon->width() / 2); |
| 190 | QCOMPARE(icon->y(), contentY); |
| 191 | QCOMPARE(icon->width(), icon->implicitWidth()); |
| 192 | QCOMPARE(icon->height(), icon->implicitHeight()); |
| 193 | QCOMPARE(text->x(), horizontalCenter - text->width() / 2); |
| 194 | QCOMPARE(text->y(), contentY + icon->height() + label->spacing()); |
| 195 | QCOMPARE(text->width(), text->implicitWidth()); |
| 196 | QCOMPARE(text->height(), text->implicitHeight()); |
| 197 | QCOMPARE(label->implicitWidth(), qMax(icon->implicitWidth(), text->implicitWidth()) + horizontalPadding); |
| 198 | QCOMPARE(label->implicitHeight(), combinedHeight + verticalPadding); |
| 199 | break; |
| 200 | } |
| 201 | case QQuickIconLabel::TextBesideIcon: |
| 202 | default: |
| 203 | QVERIFY(icon); |
| 204 | QVERIFY(text); |
| 205 | const qreal combinedWidth = icon->width() + label->spacing() + text->width(); |
| 206 | const qreal contentX = horizontalCenter - combinedWidth / 2; |
| 207 | QCOMPARE(icon->x(), contentX + (label->isMirrored() ? text->width() + label->spacing() : 0)); |
| 208 | QCOMPARE(icon->y(), verticalCenter - icon->height() / 2); |
| 209 | QCOMPARE(icon->width(), icon->implicitWidth()); |
| 210 | QCOMPARE(icon->height(), icon->implicitHeight()); |
| 211 | QCOMPARE(text->x(), contentX + (label->isMirrored() ? 0 : icon->width() + label->spacing())); |
| 212 | QCOMPARE(text->y(), verticalCenter - text->height() / 2); |
| 213 | QCOMPARE(text->width(), text->implicitWidth()); |
| 214 | QCOMPARE(text->height(), text->implicitHeight()); |
| 215 | QCOMPARE(label->implicitWidth(), combinedWidth + horizontalPadding); |
| 216 | QCOMPARE(label->implicitHeight(), qMax(icon->implicitHeight(), text->implicitHeight()) + verticalPadding); |
| 217 | break; |
| 218 | } |
| 219 | |
| 220 | if (text) |
| 221 | QCOMPARE(label->baselineOffset(), text->y() + text->baselineOffset()); |
| 222 | else |
| 223 | QCOMPARE(label->baselineOffset(), 0); |
| 224 | } |
| 225 | } |
| 226 | |
| 227 | void tst_qquickiconlabel::spacingWithOneDelegate_data() |
| 228 | { |
| 229 | QTest::addColumn<QString>(name: "qmlFileName" ); |
| 230 | |
| 231 | QTest::addRow(format: "spacingWithOnlyIcon" ) << QStringLiteral("spacingWithOnlyIcon.qml" ); |
| 232 | QTest::addRow(format: "spacingWithOnlyText" ) << QStringLiteral("spacingWithOnlyText.qml" ); |
| 233 | } |
| 234 | |
| 235 | void tst_qquickiconlabel::spacingWithOneDelegate() |
| 236 | { |
| 237 | QFETCH(QString, qmlFileName); |
| 238 | |
| 239 | QQuickView view(testFileUrl(fileName: qmlFileName)); |
| 240 | QCOMPARE(view.status(), QQuickView::Ready); |
| 241 | view.show(); |
| 242 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
| 243 | |
| 244 | QQuickItem *rootItem = view.rootObject(); |
| 245 | QVERIFY(rootItem); |
| 246 | |
| 247 | QQuickIconLabel *label = rootItem->findChild<QQuickIconLabel *>(); |
| 248 | QVERIFY(label); |
| 249 | QQuickItem *delegate = nullptr; |
| 250 | if (!label->icon().isEmpty()) { |
| 251 | QVERIFY(!label->findChild<QQuickText *>()); |
| 252 | delegate = label->findChild<QQuickIconImage *>(); |
| 253 | } else { |
| 254 | QVERIFY(!label->findChild<QQuickIconImage *>()); |
| 255 | delegate = label->findChild<QQuickText *>(); |
| 256 | } |
| 257 | |
| 258 | QVERIFY(delegate); |
| 259 | QCOMPARE(delegate->x(), 0.0); |
| 260 | QCOMPARE(delegate->width(), label->width()); |
| 261 | } |
| 262 | |
| 263 | void tst_qquickiconlabel::emptyIconSource() |
| 264 | { |
| 265 | QQuickView view(testFileUrl(fileName: "iconlabel.qml" )); |
| 266 | QCOMPARE(view.status(), QQuickView::Ready); |
| 267 | view.show(); |
| 268 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
| 269 | |
| 270 | QQuickItem *rootItem = view.rootObject(); |
| 271 | QVERIFY(rootItem); |
| 272 | |
| 273 | QQuickIconLabel *label = rootItem->findChild<QQuickIconLabel *>(); |
| 274 | QVERIFY(label); |
| 275 | QCOMPARE(label->spacing(), 0.0); |
| 276 | QCOMPARE(label->display(), QQuickIconLabel::TextBesideIcon); |
| 277 | QCOMPARE(label->isMirrored(), false); |
| 278 | |
| 279 | QQuickItem *icon = label->findChild<QQuickIconImage *>(); |
| 280 | QVERIFY(icon); |
| 281 | |
| 282 | QQuickItem *text = label->findChild<QQuickText *>(); |
| 283 | QVERIFY(text); |
| 284 | qreal horizontalCenter = label->width() / 2; |
| 285 | const qreal combinedWidth = icon->width() + text->width(); |
| 286 | const qreal contentX = horizontalCenter - combinedWidth / 2; |
| 287 | // The text should be positioned next to an item. |
| 288 | QCOMPARE(text->x(), contentX + icon->width() + label->spacing()); |
| 289 | |
| 290 | // Now give the label an explicit width large enough so that implicit size |
| 291 | // changes in its children don't affect its implicit size. |
| 292 | label->setWidth(label->implicitWidth() + 200); |
| 293 | label->setHeight(label->implicitWidth() + 100); |
| 294 | QVERIFY(icon->property("source" ).isValid()); |
| 295 | label->setIcon(QQuickIcon()); |
| 296 | QVERIFY(!label->findChild<QQuickIconImage *>()); |
| 297 | horizontalCenter = label->width() / 2; |
| 298 | QCOMPARE(text->x(), horizontalCenter - text->width() / 2); |
| 299 | } |
| 300 | |
| 301 | void tst_qquickiconlabel::colorChanges() |
| 302 | { |
| 303 | if (QGuiApplication::platformName() == QLatin1String("offscreen" )) |
| 304 | QSKIP("grabToImage() doesn't work on the \"offscreen\" platform plugin (QTBUG-63185)" ); |
| 305 | |
| 306 | QQuickView view(testFileUrl(fileName: "colorChanges.qml" )); |
| 307 | QCOMPARE(view.status(), QQuickView::Ready); |
| 308 | view.show(); |
| 309 | QVERIFY(QTest::qWaitForWindowExposed(&view)); |
| 310 | |
| 311 | QQuickItem *rootItem = view.rootObject(); |
| 312 | QVERIFY(rootItem); |
| 313 | |
| 314 | QQuickIconLabel *label = rootItem->findChild<QQuickIconLabel *>(); |
| 315 | QVERIFY(label); |
| 316 | QCOMPARE(label->spacing(), 0.0); |
| 317 | QCOMPARE(label->display(), QQuickIconLabel::TextBesideIcon); |
| 318 | QCOMPARE(label->isMirrored(), false); |
| 319 | |
| 320 | QSharedPointer<QQuickItemGrabResult> grabResult = label->grabToImage(); |
| 321 | QTRY_VERIFY(!grabResult->image().isNull()); |
| 322 | const QImage enabledImageGrab = grabResult->image(); |
| 323 | |
| 324 | // The color should change to "red" when the item is disabled. |
| 325 | rootItem->setEnabled(false); |
| 326 | |
| 327 | grabResult = label->grabToImage(); |
| 328 | QTRY_VERIFY(!grabResult->image().isNull()); |
| 329 | QVERIFY(grabResult->image() != enabledImageGrab); |
| 330 | } |
| 331 | |
| 332 | QTEST_MAIN(tst_qquickiconlabel) |
| 333 | |
| 334 | #include "tst_qquickiconlabel.moc" |
| 335 | |