diff options
author | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2021-11-18 16:58:01 +0100 |
---|---|---|
committer | Volker Hilsheimer <volker.hilsheimer@qt.io> | 2021-11-26 09:36:07 +0100 |
commit | 77de4a9bb4e15d19bd3f87f03f4b2d06a68277b5 (patch) | |
tree | 07c2fdb4ff6a8db9cbc7109a03d4e09f8094c2da /tests | |
parent | 00ea6f58dadc1dc199ab52ae06594e9a4e39ef3d (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.txt | 1 | ||||
-rw-r--r-- | tests/baseline/stylesheet/CMakeLists.txt | 28 | ||||
-rw-r--r-- | tests/baseline/stylesheet/icons.qrc | 9 | ||||
-rw-r--r-- | tests/baseline/stylesheet/icons/align-center.png | bin | 0 -> 1495 bytes | |||
-rw-r--r-- | tests/baseline/stylesheet/icons/align-left.png | bin | 0 -> 1496 bytes | |||
-rw-r--r-- | tests/baseline/stylesheet/icons/align-right.png | bin | 0 -> 1595 bytes | |||
-rw-r--r-- | tests/baseline/stylesheet/icons/arrow-up.png | bin | 0 -> 5935 bytes | |||
-rw-r--r-- | tests/baseline/stylesheet/qss/default.qss | 0 | ||||
-rw-r--r-- | tests/baseline/stylesheet/qss/qtoolbutton/no_border.qss | 1 | ||||
-rw-r--r-- | tests/baseline/stylesheet/qss/qtoolbutton/styled.qss | 38 | ||||
-rw-r--r-- | tests/baseline/stylesheet/qss/qtoolbutton/styled_no_border.qss | 42 | ||||
-rw-r--r-- | tests/baseline/stylesheet/stylesheet.pro | 10 | ||||
-rw-r--r-- | tests/baseline/stylesheet/tst_baseline_stylesheet.cpp | 261 |
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 Binary files differnew file mode 100644 index 0000000000..a7ce2fad52 --- /dev/null +++ b/tests/baseline/stylesheet/icons/align-center.png diff --git a/tests/baseline/stylesheet/icons/align-left.png b/tests/baseline/stylesheet/icons/align-left.png Binary files differnew file mode 100644 index 0000000000..ad5b975480 --- /dev/null +++ b/tests/baseline/stylesheet/icons/align-left.png diff --git a/tests/baseline/stylesheet/icons/align-right.png b/tests/baseline/stylesheet/icons/align-right.png Binary files differnew file mode 100644 index 0000000000..7ebfd6dd35 --- /dev/null +++ b/tests/baseline/stylesheet/icons/align-right.png diff --git a/tests/baseline/stylesheet/icons/arrow-up.png b/tests/baseline/stylesheet/icons/arrow-up.png Binary files differnew file mode 100644 index 0000000000..70c43a7c62 --- /dev/null +++ b/tests/baseline/stylesheet/icons/arrow-up.png 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" |