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 | |