summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorVolker Hilsheimer <volker.hilsheimer@qt.io>2021-11-18 16:58:01 +0100
committerVolker Hilsheimer <volker.hilsheimer@qt.io>2021-11-26 09:36:07 +0100
commit77de4a9bb4e15d19bd3f87f03f4b2d06a68277b5 (patch)
tree07c2fdb4ff6a8db9cbc7109a03d4e09f8094c2da /tests
parent00ea6f58dadc1dc199ab52ae06594e9a4e39ef3d (diff)
Fix and complete style sheet support for QToolButton
Amends 2b2e7b2ac50e5b4f6e1888e594f6e32338dd2a80, which rewrote the rendering to remove the conflation of menu arrows and arrow icons, but introduced double rendering of the arrow icons if only the border was styled. Add a baseline test for style sheets, with a test function for QToolButton configured in various ways and styled with different style sheets. The new test case includes a Qt 5 build system so that we can compare Qt 5.15 with Qt 6. Fixes: QTBUG-98286 Pick-to: 6.2 6.2.2 Change-Id: I09cdc829c1a7e7913df4c3768dbe44b6dba4778b Reviewed-by: Richard Moe Gustavsen <richard.gustavsen@qt.io> Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
Diffstat (limited to 'tests')
-rw-r--r--tests/baseline/CMakeLists.txt1
-rw-r--r--tests/baseline/stylesheet/CMakeLists.txt28
-rw-r--r--tests/baseline/stylesheet/icons.qrc9
-rw-r--r--tests/baseline/stylesheet/icons/align-center.pngbin0 -> 1495 bytes
-rw-r--r--tests/baseline/stylesheet/icons/align-left.pngbin0 -> 1496 bytes
-rw-r--r--tests/baseline/stylesheet/icons/align-right.pngbin0 -> 1595 bytes
-rw-r--r--tests/baseline/stylesheet/icons/arrow-up.pngbin0 -> 5935 bytes
-rw-r--r--tests/baseline/stylesheet/qss/default.qss0
-rw-r--r--tests/baseline/stylesheet/qss/qtoolbutton/no_border.qss1
-rw-r--r--tests/baseline/stylesheet/qss/qtoolbutton/styled.qss38
-rw-r--r--tests/baseline/stylesheet/qss/qtoolbutton/styled_no_border.qss42
-rw-r--r--tests/baseline/stylesheet/stylesheet.pro10
-rw-r--r--tests/baseline/stylesheet/tst_baseline_stylesheet.cpp261
13 files changed, 390 insertions, 0 deletions
diff --git a/tests/baseline/CMakeLists.txt b/tests/baseline/CMakeLists.txt
index 28a1910fd2..dadfa1ba7d 100644
--- a/tests/baseline/CMakeLists.txt
+++ b/tests/baseline/CMakeLists.txt
@@ -3,4 +3,5 @@ if(TARGET Qt::Network)
endif()
if(TARGET Qt::Network AND TARGET Qt::Widgets)
add_subdirectory(widgets)
+ add_subdirectory(stylesheet)
endif()
diff --git a/tests/baseline/stylesheet/CMakeLists.txt b/tests/baseline/stylesheet/CMakeLists.txt
new file mode 100644
index 0000000000..5129f1691c
--- /dev/null
+++ b/tests/baseline/stylesheet/CMakeLists.txt
@@ -0,0 +1,28 @@
+file(GLOB_RECURSE test_data_glob
+ RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
+ qss/*)
+list(APPEND test_data ${test_data_glob})
+
+qt_internal_add_test(tst_baseline_stylesheet
+ SOURCES
+ ../shared/baselineprotocol.cpp ../shared/baselineprotocol.h ../shared/lookup3.cpp
+ ../shared/qbaselinetest.cpp ../shared/qbaselinetest.h
+ tst_baseline_stylesheet.cpp
+ INCLUDE_DIRECTORIES
+ ../shared
+ PUBLIC_LIBRARIES
+ Qt::Gui
+ Qt::Widgets
+ Qt::Network
+ TESTDATA ${test_data}
+)
+
+qt6_add_resources(tst_baseline_stylesheet "tst_baseline_stylesheet"
+ PREFIX
+ "/"
+ FILES
+ "icons/align-center.png"
+ "icons/align-left.png"
+ "icons/align-right.png"
+ "icons/arrow-up.png"
+)
diff --git a/tests/baseline/stylesheet/icons.qrc b/tests/baseline/stylesheet/icons.qrc
new file mode 100644
index 0000000000..8b3e7ca6cc
--- /dev/null
+++ b/tests/baseline/stylesheet/icons.qrc
@@ -0,0 +1,9 @@
+<!DOCTYPE RCC>
+<RCC version="1.0">
+<qresource>
+ <file>icons/align-center.png</file>
+ <file>icons/align-left.png</file>
+ <file>icons/align-right.png</file>
+ <file>icons/arrow-up.png</file>
+</qresource>
+</RCC>
diff --git a/tests/baseline/stylesheet/icons/align-center.png b/tests/baseline/stylesheet/icons/align-center.png
new file mode 100644
index 0000000000..a7ce2fad52
--- /dev/null
+++ b/tests/baseline/stylesheet/icons/align-center.png
Binary files differ
diff --git a/tests/baseline/stylesheet/icons/align-left.png b/tests/baseline/stylesheet/icons/align-left.png
new file mode 100644
index 0000000000..ad5b975480
--- /dev/null
+++ b/tests/baseline/stylesheet/icons/align-left.png
Binary files differ
diff --git a/tests/baseline/stylesheet/icons/align-right.png b/tests/baseline/stylesheet/icons/align-right.png
new file mode 100644
index 0000000000..7ebfd6dd35
--- /dev/null
+++ b/tests/baseline/stylesheet/icons/align-right.png
Binary files differ
diff --git a/tests/baseline/stylesheet/icons/arrow-up.png b/tests/baseline/stylesheet/icons/arrow-up.png
new file mode 100644
index 0000000000..70c43a7c62
--- /dev/null
+++ b/tests/baseline/stylesheet/icons/arrow-up.png
Binary files differ
diff --git a/tests/baseline/stylesheet/qss/default.qss b/tests/baseline/stylesheet/qss/default.qss
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/baseline/stylesheet/qss/default.qss
diff --git a/tests/baseline/stylesheet/qss/qtoolbutton/no_border.qss b/tests/baseline/stylesheet/qss/qtoolbutton/no_border.qss
new file mode 100644
index 0000000000..0c9744de7c
--- /dev/null
+++ b/tests/baseline/stylesheet/qss/qtoolbutton/no_border.qss
@@ -0,0 +1 @@
+border: none
diff --git a/tests/baseline/stylesheet/qss/qtoolbutton/styled.qss b/tests/baseline/stylesheet/qss/qtoolbutton/styled.qss
new file mode 100644
index 0000000000..799be9bf31
--- /dev/null
+++ b/tests/baseline/stylesheet/qss/qtoolbutton/styled.qss
@@ -0,0 +1,38 @@
+QToolButton::menu-button {
+ border: 2px solid gray;
+ border-top-right-radius: 6px;
+ border-bottom-right-radius: 6px;
+ /* 16px width + 4px for border = 20px allocated above */
+ width: 16px;
+}
+
+QToolButton::menu-indicator {
+ image: url(:/icons/arrow-up.png);
+ width: 16px;
+ height: 16px;
+ subcontrol-position: right bottom;
+}
+
+QToolButton::menu-arrow {
+ subcontrol-position: bottom right;
+ image: url(:/icons/arrow-up.png);
+}
+QToolButton::down-arrow {
+ image: url(:/icons/arrow-up.png);
+ background-color: blue
+}
+QToolButton::up-arrow {
+ image: url(:/icons/arrow-up.png);
+ background-color: green
+}
+QToolButton::left-arrow {
+ image: url(:/icons/arrow-up.png);
+ background-color: red
+}
+QToolButton::right-arrow {
+ image: url(:/icons/arrow-up.png);
+ background-color: cyan;
+ width: 15px;
+ height: 15px;
+ subcontrol-position: right bottom;
+}
diff --git a/tests/baseline/stylesheet/qss/qtoolbutton/styled_no_border.qss b/tests/baseline/stylesheet/qss/qtoolbutton/styled_no_border.qss
new file mode 100644
index 0000000000..7cb753120f
--- /dev/null
+++ b/tests/baseline/stylesheet/qss/qtoolbutton/styled_no_border.qss
@@ -0,0 +1,42 @@
+QToolButton {
+ border: none
+}
+
+QToolButton::menu-button {
+ border: 2px solid gray;
+ border-top-right-radius: 6px;
+ border-bottom-right-radius: 6px;
+ /* 16px width + 4px for border = 20px allocated above */
+ width: 16px;
+}
+
+QToolButton::menu-indicator {
+ image: url(:/icons/arrow-up.png);
+ width: 16px;
+ height: 16px;
+ subcontrol-position: right bottom;
+}
+
+QToolButton::menu-arrow {
+ subcontrol-position: bottom right;
+ image: url(:/icons/arrow-up.png);
+}
+QToolButton::down-arrow {
+ image: url(:/icons/arrow-up.png);
+ background-color: blue
+}
+QToolButton::up-arrow {
+ image: url(:/icons/arrow-up.png);
+ background-color: green
+}
+QToolButton::left-arrow {
+ image: url(:/icons/arrow-up.png);
+ background-color: red
+}
+QToolButton::right-arrow {
+ image: url(:/icons/arrow-up.png);
+ background-color: cyan;
+ width: 15px;
+ height: 15px;
+ subcontrol-position: right bottom;
+}
diff --git a/tests/baseline/stylesheet/stylesheet.pro b/tests/baseline/stylesheet/stylesheet.pro
new file mode 100644
index 0000000000..8c6d79124c
--- /dev/null
+++ b/tests/baseline/stylesheet/stylesheet.pro
@@ -0,0 +1,10 @@
+CONFIG += testcase
+TARGET = tst_baseline_stylesheet
+QT += widgets testlib gui-private
+
+SOURCES += tst_baseline_stylesheet.cpp
+RESOURCES += icons.qrc
+
+include($$PWD/../shared/qbaselinetest.pri)
+
+TESTDATA += qss/*
diff --git a/tests/baseline/stylesheet/tst_baseline_stylesheet.cpp b/tests/baseline/stylesheet/tst_baseline_stylesheet.cpp
new file mode 100644
index 0000000000..b755237b30
--- /dev/null
+++ b/tests/baseline/stylesheet/tst_baseline_stylesheet.cpp
@@ -0,0 +1,261 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 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 <qbaselinetest.h>
+#include <QtWidgets>
+#include <QByteArray>
+
+class tst_Stylesheet : public QObject
+{
+ Q_OBJECT
+
+public:
+ tst_Stylesheet();
+
+ QWidget *testWindow() const { return window; }
+ void loadTestFiles();
+
+private slots:
+ void initTestCase();
+ void init();
+ void cleanup();
+
+ void tst_QToolButton_data();
+ void tst_QToolButton();
+
+private:
+ void makeVisible();
+ QImage takeSnapshot();
+ QDir styleSheetDir;
+
+ QWidget *window = nullptr;
+};
+
+tst_Stylesheet::tst_Stylesheet()
+{
+ QBaselineTest::addClientProperty("Project", "Widgets");
+
+ // Set key platform properties that are relevant for the appearance of widgets
+ const QString platformName = QGuiApplication::platformName() + "-" + QSysInfo::productType();
+ QBaselineTest::addClientProperty("PlatformName", platformName);
+ QBaselineTest::addClientProperty("OSVersion", QSysInfo::productVersion());
+
+ // Encode a number of parameters that impact the UI
+ QPalette palette;
+ QFont font;
+ QByteArray appearanceBytes;
+ {
+ QDataStream appearanceStream(&appearanceBytes, QIODevice::WriteOnly);
+ appearanceStream << palette << font <<
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ QApplication::style()->metaObject()->className();
+#else
+ QApplication::style()->name();
+#endif
+ const qreal screenDpr = QApplication::primaryScreen()->devicePixelRatio();
+ if (screenDpr != 1.0)
+ qWarning() << "DPR is" << screenDpr << "- images will be scaled";
+ }
+#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
+ const quint16 appearanceId = qChecksum(appearanceBytes, appearanceBytes.size());
+#else
+ const quint16 appearanceId = qChecksum(appearanceBytes);
+#endif
+
+ // Assume that text that's darker than the background means we run in light mode
+ // This results in a more meaningful appearance ID between different runs than
+ // just the checksum of the various attributes.
+ const QColor windowColor = palette.window().color();
+ const QColor textColor = palette.text().color();
+ const QString appearanceIdString = (windowColor.value() > textColor.value()
+ ? QString("light-%1") : QString("dark-%1"))
+ .arg(appearanceId, 0, 16);
+ QBaselineTest::addClientProperty("AppearanceID", appearanceIdString);
+
+ // let users know where they can find the results
+ qDebug() << "PlatformName computed to be:" << platformName;
+ qDebug() << "Appearance ID computed as:" << appearanceIdString;
+}
+
+void tst_Stylesheet::initTestCase()
+{
+ QString baseDir = QFINDTESTDATA("qss/default.qss");
+ styleSheetDir = QDir(QFileInfo(baseDir).path());
+
+ // Check and setup the environment. Failure to do so skips the test.
+ QByteArray msg;
+ if (!QBaselineTest::connectToBaselineServer(&msg))
+ QSKIP(msg);
+}
+
+void tst_Stylesheet::init()
+{
+ QFETCH(QString, styleSheet);
+
+ QVERIFY(!window);
+ window = new QWidget;
+ window->setWindowTitle(QTest::currentDataTag());
+#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
+ window->setScreen(QGuiApplication::primaryScreen());
+#endif
+ window->move(QGuiApplication::primaryScreen()->availableGeometry().topLeft());
+ window->setStyleSheet(styleSheet);
+}
+
+void tst_Stylesheet::loadTestFiles()
+{
+ QTest::addColumn<QString>("styleSheet");
+
+ QStringList qssFiles;
+ // first add generic test files
+ for (const auto &qssFile : styleSheetDir.entryList({QStringLiteral("*.qss")}, QDir::Files | QDir::Readable))
+ qssFiles << styleSheetDir.absoluteFilePath(qssFile);
+
+ // then test-function specific files
+ const QString testFunction = QString(QTest::currentTestFunction()).remove("tst_").toLower();
+ if (styleSheetDir.cd(testFunction)) {
+ for (const auto &qssFile : styleSheetDir.entryList({QStringLiteral("*.qss")}, QDir::Files | QDir::Readable))
+ qssFiles << styleSheetDir.absoluteFilePath(qssFile);
+ styleSheetDir.cdUp();
+ }
+
+ for (const auto &qssFile : qssFiles) {
+ QFileInfo fileInfo(qssFile);
+ QFile file(qssFile);
+ file.open(QFile::ReadOnly);
+ QString styleSheet = QString::fromUtf8(file.readAll());
+ QBaselineTest::newRow(fileInfo.baseName().toUtf8()) << styleSheet;
+ }
+}
+
+void tst_Stylesheet::makeVisible()
+{
+ window->show();
+ window->window()->windowHandle()->requestActivate();
+ // explicitly unset focus, the test needs to control when focus is shown
+ if (window->focusWidget())
+ window->focusWidget()->clearFocus();
+ QVERIFY(QTest::qWaitForWindowActive(window));
+}
+
+/*
+ Always return images scaled to a DPR of 1.0.
+
+ This might produce some fuzzy differences, but lets us
+ compare those.
+*/
+QImage tst_Stylesheet::takeSnapshot()
+{
+ QGuiApplication::processEvents();
+ QPixmap pm = window->grab();
+ QTransform scaleTransform = QTransform::fromScale(1.0 / pm.devicePixelRatioF(), 1.0 / pm.devicePixelRatioF());
+ return pm.toImage().transformed(scaleTransform, Qt::SmoothTransformation);
+}
+
+void tst_Stylesheet::cleanup()
+{
+ delete window;
+ window = nullptr;
+}
+
+void tst_Stylesheet::tst_QToolButton_data()
+{
+ loadTestFiles();
+}
+
+void tst_Stylesheet::tst_QToolButton()
+{
+ const QIcon fileIcon = QApplication::style()->standardIcon(QStyle::SP_FileIcon);
+
+ QVBoxLayout *vbox = new QVBoxLayout;
+
+ QHBoxLayout *normalButtons = new QHBoxLayout;
+ for (const auto &buttonStyle : {Qt::ToolButtonIconOnly, Qt::ToolButtonTextOnly,
+ Qt::ToolButtonTextUnderIcon, Qt::ToolButtonTextBesideIcon}) {
+ QToolButton *normal = new QToolButton;
+ normal->setToolButtonStyle(buttonStyle);
+ normal->setText("Text");
+ normal->setIcon(fileIcon);
+ normalButtons->addWidget(normal);
+ }
+ vbox->addLayout(normalButtons);
+
+ QHBoxLayout *arrowButtons = new QHBoxLayout;
+ for (const auto &arrowType : {Qt::LeftArrow, Qt::RightArrow, Qt::UpArrow, Qt::DownArrow}) {
+ QToolButton *arrow = new QToolButton;
+ arrow->setText("Text");
+ arrow->setArrowType(arrowType);
+ arrowButtons->addWidget(arrow);
+ }
+ vbox->addLayout(arrowButtons);
+
+ QHBoxLayout *arrowWithTextButtons = new QHBoxLayout;
+ for (const auto &buttonStyle : {Qt::ToolButtonTextOnly,
+ Qt::ToolButtonTextUnderIcon, Qt::ToolButtonTextBesideIcon}) {
+ QToolButton *arrow = new QToolButton;
+ arrow->setText("Text");
+ arrow->setArrowType(Qt::UpArrow);
+ arrow->setToolButtonStyle(buttonStyle);
+ arrowWithTextButtons->addWidget(arrow);
+ }
+ vbox->addLayout(arrowWithTextButtons);
+
+ QHBoxLayout *menuButtons = new QHBoxLayout;
+ for (const auto &popupMode : {QToolButton::InstantPopup, QToolButton::MenuButtonPopup,
+ QToolButton::DelayedPopup}) {
+ QToolButton *menuButton = new QToolButton;
+ menuButton->setText("Text");
+ menuButton->setIcon(fileIcon);
+ QMenu *menuButtonMenu = new QMenu;
+ menuButtonMenu->addAction(QIcon(":/icons/align-left.png"), "Left");
+ menuButtonMenu->addAction(QIcon(":/icons/align-right.png"), "Right");
+ menuButtonMenu->addAction(QIcon(":/icons/align-center.png"), "Center");
+ menuButton->setMenu(menuButtonMenu);
+ menuButton->setPopupMode(popupMode);
+ menuButtons->addWidget(menuButton);
+ }
+ vbox->addLayout(menuButtons);
+ testWindow()->setLayout(vbox);
+
+ makeVisible();
+ QBASELINE_TEST(takeSnapshot());
+}
+
+#define main _realmain
+QTEST_MAIN(tst_Stylesheet)
+#undef main
+
+int main(int argc, char *argv[])
+{
+ qSetGlobalQHashSeed(0); // Avoid rendering variations caused by QHash randomization
+
+ QBaselineTest::handleCmdLineArgs(&argc, &argv);
+ return _realmain(argc, argv);
+}
+
+#include "tst_baseline_stylesheet.moc"