aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMitch Curtis <mitch.curtis@qt.io>2023-09-25 17:18:41 +0800
committerMitch Curtis <mitch.curtis@qt.io>2023-09-29 01:51:20 +0000
commit9427ee785c832db191da80402c8f40ec3ae81324 (patch)
treeea44fa66f6803f75714b4227b5b12559af1fe8ac
parentcacb0ea963ae70f909246c1c1b639f2f78a3a003 (diff)
Fix Material dark theme not being respected when used as a fallback
The fallback theme was previously not being initialized if the style plugin for which registerTypes was called was not the current style; that is, only the current style would have its theme initialized. As the Material (and Universal) style's settings such as light/dark theme are taken into use in its style plugin's initializeTheme function, we must call that. The fallback style's theme is now initialized before the current style's theme, meaning that any initialization custom styles' themes may do in the future (if QTBUG-67062 is implemented and the theming API becomes public) will overwrite any shared font/palette values, as expected. [ChangeLog][Controls][Important Behavior Changes] The fallback style's theme is now initialized, allowing e.g. the Material style's dark theme setting to be respected when it's set as the fallback style and the user is using run-time style selection. Compile-time style selection is unaffected and continues to work correctly. Task-number: QTBUG-86355 Task-number: QTBUG-117403 Change-Id: Ic651816592c8ca828cfc245be738dac20d89be46 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--src/quickcontrols/qquickstyleplugin.cpp23
-rw-r--r--tests/auto/quickcontrols/styleimports/data/applicationWindowWithButton.qml3
-rw-r--r--tests/auto/quickcontrols/styleimports/data/importStyleWithQmlDirFallback.qml17
-rw-r--r--tests/auto/quickcontrols/styleimports/data/styles/FileSystemStyle/Button.qml5
-rw-r--r--tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsMaterial/Button.qml34
-rw-r--r--tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsMaterial/qmldir3
-rw-r--r--tests/auto/quickcontrols/styleimports/tst_styleimports.cpp123
7 files changed, 201 insertions, 7 deletions
diff --git a/src/quickcontrols/qquickstyleplugin.cpp b/src/quickcontrols/qquickstyleplugin.cpp
index 5b2613eba7..caae034970 100644
--- a/src/quickcontrols/qquickstyleplugin.cpp
+++ b/src/quickcontrols/qquickstyleplugin.cpp
@@ -54,18 +54,31 @@ void QQuickStylePlugin::registerTypes(const char *uri)
theme = createTheme(effectiveCurrentStyleName);
}
- if (name() != effectiveCurrentStyleName) {
- qCDebug(lcStylePlugin).nospace() << "theme does not belong to current style ("
- << effectiveCurrentStyleName << "); not calling initializeTheme()";
+ // The primary fallback is the style set by the user. We need to check for that here
+ // so that we can ensure that fallback styles' themes are initialized (QTBUG-117403)
+ // without also allowing the Basic style to be initialized, as it is a secondary fallback
+ // for every built-in style (and only built-in styles can be fallbacks).
+ const bool thisPluginBelongsToCurrentStyle = name() == effectiveCurrentStyleName;
+ const bool isPrimaryFallback = name() == QQuickStylePrivate::fallbackStyle();
+ if (!thisPluginBelongsToCurrentStyle && !isPrimaryFallback) {
+ qCDebug(lcStylePlugin).nospace() << "this style plugin does not belong to the current ("
+ << effectiveCurrentStyleName << ") or fallback (" << QQuickStylePrivate::fallbackStyle()
+ << ") style; not calling initializeTheme()";
return;
}
- qCDebug(lcStylePlugin) << "theme has not yet been initialized; calling initializeTheme()";
+ if (thisPluginBelongsToCurrentStyle) {
+ qCDebug(lcStylePlugin).nospace() << "this style plugin belongs to the current style "
+ << effectiveCurrentStyleName << "; calling initializeTheme()";
+ } else {
+ qCDebug(lcStylePlugin).nospace() << "this style plugin belongs to the fallback style "
+ << QQuickStylePrivate::fallbackStyle() << "; calling initializeTheme()";
+ }
initializeTheme(theme);
connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged,
this, &QQuickStylePlugin::updateTheme);
- if (!styleName.isEmpty())
+ if (!isPrimaryFallback && !styleName.isEmpty())
QFileSelectorPrivate::addStatics(QStringList() << styleName);
}
diff --git a/tests/auto/quickcontrols/styleimports/data/applicationWindowWithButton.qml b/tests/auto/quickcontrols/styleimports/data/applicationWindowWithButton.qml
index 512bd0bb08..52111a143c 100644
--- a/tests/auto/quickcontrols/styleimports/data/applicationWindowWithButton.qml
+++ b/tests/auto/quickcontrols/styleimports/data/applicationWindowWithButton.qml
@@ -1,7 +1,6 @@
-// Copyright (C) 2020 The Qt Company Ltd.
+// Copyright (C) 2023 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
-import QtQuick
import QtQuick.Controls
ApplicationWindow {
diff --git a/tests/auto/quickcontrols/styleimports/data/importStyleWithQmlDirFallback.qml b/tests/auto/quickcontrols/styleimports/data/importStyleWithQmlDirFallback.qml
new file mode 100644
index 0000000000..443e395351
--- /dev/null
+++ b/tests/auto/quickcontrols/styleimports/data/importStyleWithQmlDirFallback.qml
@@ -0,0 +1,17 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import StyleThatImportsMaterial
+
+ApplicationWindow {
+ title: "Test Application Window"
+ width: 400
+ height: 400
+
+ property alias button: button
+
+ Button {
+ id: button
+ text: "QmlOnly Button"
+ }
+}
diff --git a/tests/auto/quickcontrols/styleimports/data/styles/FileSystemStyle/Button.qml b/tests/auto/quickcontrols/styleimports/data/styles/FileSystemStyle/Button.qml
index a5078b14c2..71c451ab0f 100644
--- a/tests/auto/quickcontrols/styleimports/data/styles/FileSystemStyle/Button.qml
+++ b/tests/auto/quickcontrols/styleimports/data/styles/FileSystemStyle/Button.qml
@@ -1,4 +1,9 @@
import QtQuick.Templates as T
T.Button {
+ id: control
objectName: "FileSystemStyle"
+ contentItem: T.Label {
+ text: control.text
+ color: "#0000ff"
+ }
}
diff --git a/tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsMaterial/Button.qml b/tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsMaterial/Button.qml
new file mode 100644
index 0000000000..a0355dd215
--- /dev/null
+++ b/tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsMaterial/Button.qml
@@ -0,0 +1,34 @@
+// Copyright (C) 2023 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
+
+import QtQuick
+import QtQuick.Templates as T
+
+T.Button {
+ id: control
+
+ implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
+ implicitContentWidth + leftPadding + rightPadding)
+ implicitHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset,
+ implicitContentHeight + topPadding + bottomPadding)
+
+ padding: 6
+ horizontalPadding: padding + 2
+ spacing: 6
+
+ contentItem: T.Label {
+ text: control.text
+ font: control.font
+ color: "#ff0000"
+ verticalAlignment: T.Label.AlignVCenter
+ }
+
+ background: Rectangle {
+ implicitWidth: 100
+ implicitHeight: 40
+ visible: !control.flat || control.down || control.checked || control.highlighted
+ color: "#ccc"
+ border.color: control.palette.highlight
+ border.width: control.visualFocus ? 2 : 0
+ }
+}
diff --git a/tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsMaterial/qmldir b/tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsMaterial/qmldir
new file mode 100644
index 0000000000..eeffe70d4e
--- /dev/null
+++ b/tests/auto/quickcontrols/styleimports/data/styles/StyleThatImportsMaterial/qmldir
@@ -0,0 +1,3 @@
+module StyleThatImportsMaterial
+Button 1.0 Button.qml
+import QtQuick.Controls.Material
diff --git a/tests/auto/quickcontrols/styleimports/tst_styleimports.cpp b/tests/auto/quickcontrols/styleimports/tst_styleimports.cpp
index 175541296a..2fc86b2d76 100644
--- a/tests/auto/quickcontrols/styleimports/tst_styleimports.cpp
+++ b/tests/auto/quickcontrols/styleimports/tst_styleimports.cpp
@@ -15,7 +15,12 @@
#include <QtQuickControls2/qquickstyle.h>
#include <QtQuickControls2/private/qquickstyle_p.h>
#include <QtQuickControls2Impl/private/qquickiconlabel_p.h>
+#include <QtQuickControlsTestUtils/private/controlstestutils_p.h>
#include <QtQuickControlsTestUtils/private/qtest_quickcontrols_p.h>
+#include <QtQuickTemplates2/private/qquickapplicationwindow_p.h>
+#include <QtQuickTemplates2/private/qquickbutton_p.h>
+
+using namespace QQuickControlsTestUtils;
class tst_StyleImports : public QQmlDataTest
{
@@ -38,6 +43,9 @@ private slots:
void fallbackStyleShouldNotOverwriteTheme_data();
void fallbackStyleShouldNotOverwriteTheme();
+ void fallbackStyleThemeRespected_data();
+ void fallbackStyleThemeRespected();
+
void attachedTypesAvailable_data();
void attachedTypesAvailable();
};
@@ -278,6 +286,121 @@ void tst_StyleImports::fallbackStyleShouldNotOverwriteTheme()
QCOMPARE(contentItem->color(), expectedContentItemColor);
}
+enum FallbackMethod {
+ QmlDirImport,
+ EnvVar
+};
+
+void tst_StyleImports::fallbackStyleThemeRespected_data()
+{
+ QTest::addColumn<QString>("qmlFilePath");
+ QTest::addColumn<QString>("runtimeStyle");
+ QTest::addColumn<FallbackMethod>("fallbackMethod");
+ QTest::addColumn<Qt::ColorScheme>("colorScheme");
+ QTest::addColumn<QColor>("expectedButtonTextColor");
+ QTest::addColumn<QColor>("expectedWindowColor");
+
+ // Taken from qquickmaterialstyle.cpp.
+ static const QRgb materialBackgroundColorLight = 0xFFFFFBFE;
+ static const QRgb materialBackgroundColorDark = 0xFF1C1B1F;
+
+ // Notes:
+ // - FileSystemStyle has blue button text.
+ // - StyleThatImportsMaterial has red button text.
+ // - All rows result in Material being the fallback.
+
+ QTest::newRow("import controls, env var fallback, light") << "applicationWindowWithButton.qml"
+ << "FileSystemStyle" << EnvVar << Qt::ColorScheme::Light
+ << QColor::fromRgb(0x0000ff) << QColor::fromRgba(materialBackgroundColorLight);
+ QTest::newRow("import controls, env var fallback, dark") << "applicationWindowWithButton.qml"
+ << "FileSystemStyle" << EnvVar << Qt::ColorScheme::Dark
+ << QColor::fromRgb(0x0000ff) << QColor::fromRgba(materialBackgroundColorDark);
+
+ QTest::newRow("import controls, qmldir fallback, light") << "applicationWindowWithButton.qml"
+ << "StyleThatImportsMaterial" << QmlDirImport << Qt::ColorScheme::Light
+ << QColor::fromRgb(0xff0000) << QColor::fromRgba(materialBackgroundColorLight);
+ QTest::newRow("import controls, qmldir fallback, dark") << "applicationWindowWithButton.qml"
+ << "StyleThatImportsMaterial" << QmlDirImport << Qt::ColorScheme::Dark
+ << QColor::fromRgb(0xff0000) << QColor::fromRgba(materialBackgroundColorDark);
+
+ QTest::newRow("import style, qmldir fallback, light") << "importStyleWithQmlDirFallback.qml"
+ << "" << QmlDirImport << Qt::ColorScheme::Light
+ << QColor::fromRgb(0xff0000) << QColor::fromRgba(materialBackgroundColorLight);
+ QTest::newRow("import style, qmldir fallback, dark") << "importStyleWithQmlDirFallback.qml"
+ << "" << QmlDirImport << Qt::ColorScheme::Dark
+ << QColor::fromRgb(0xff0000) << QColor::fromRgba(materialBackgroundColorDark);
+}
+
+// Tests that a fallback style's (the Material style, in this case) theme settings
+// are respected for both run-time and compile-time style selection.
+void tst_StyleImports::fallbackStyleThemeRespected()
+{
+ QFETCH(QString, qmlFilePath);
+ QFETCH(QString, runtimeStyle);
+ QFETCH(FallbackMethod, fallbackMethod);
+ QFETCH(Qt::ColorScheme, colorScheme);
+ QFETCH(QColor, expectedButtonTextColor);
+ QFETCH(QColor, expectedWindowColor);
+
+ const char *materialThemeEnvVarName = "QT_QUICK_CONTROLS_MATERIAL_THEME";
+ const QString originalMaterialTheme = qgetenv(materialThemeEnvVarName);
+ qputenv(materialThemeEnvVarName, colorScheme == Qt::ColorScheme::Light ? "Light" : "Dark");
+
+ // Only set this if it's not empty, because setting an empty style
+ // will still cause it be resolved and we end up using the platform default.
+ if (!runtimeStyle.isEmpty())
+ QQuickStyle::setStyle(runtimeStyle);
+
+ const char *fallbackStyleEnvVarName = "QT_QUICK_CONTROLS_FALLBACK_STYLE";
+ const QString originalFallbackStyle = qgetenv(fallbackStyleEnvVarName);
+ if (fallbackMethod == EnvVar)
+ qputenv(fallbackStyleEnvVarName, "Material");
+
+ auto cleanup = qScopeGuard([&]() {
+ qputenv(materialThemeEnvVarName, qPrintable(originalMaterialTheme));
+ qputenv(fallbackStyleEnvVarName, qPrintable(originalFallbackStyle));
+ });
+
+ QQuickControlsApplicationHelper helper(this, qmlFilePath, {},
+ QStringList() << dataDirectory() + QLatin1String("/styles"));
+ QVERIFY2(helper.ready, helper.failureMessage());
+
+ auto button = helper.window->property("button").value<QQuickButton*>();
+ QVERIFY(button);
+ // contentItem should be a label with "salmon" text color.
+ QCOMPARE(button->contentItem()->property("color").value<QColor>(), expectedButtonTextColor);
+ const QStringList skippedTestRows = {
+ // This row only fails when run on its own.
+ "import controls, qmldir fallback, dark",
+ /*
+ This is also failing for the second row when running all tests,
+ or the following tests in the given order:
+ fallbackStyleThemeRespected:"import controls, env var fallback, dark"
+ fallbackStyleThemeRespected:"import controls, qmldir fallback, light"
+ It fails because of QTBUG-117526 - the fallback style is reported as being empty because
+ it was imported via the qmldir, which QQuickStyle isn't aware of. So the
+ Material theme never gets (re-)initialized, and it retains the dark theme
+ from the previous test row. It doesn't fail when run on its own, because the default
+ Material theme is light, so it doesn't matter if it's not initialized in that case.
+ */
+ "import controls, qmldir fallback, light"
+ };
+ if (skippedTestRows.contains(QTest::currentDataTag()))
+ QSKIP("This row is unreliable depending on the order in which it is run, due to QTBUG-117526");
+ QCOMPARE(helper.appWindow->color(), expectedWindowColor);
+
+ // If using run-time style selection, check that QQuickStyle reports the correct values.
+ // QQuickStyle is not supported when using compile-time style selection.
+ if (!runtimeStyle.isEmpty()) {
+ QCOMPARE(QQuickStyle::name(), runtimeStyle);
+ // QTBUG-117526: This will fail when fallbackMethod is QmlDirImport, because
+ // QQuickStylePrivate::fallbackStyle has the wrong value when using
+ // run-time style selection and the fallback style is imported via the style's qmldir.
+ // Remove this comment when the bug is fixed.
+ QCOMPARE(QQuickStylePrivate::fallbackStyle(), "Material");
+ }
+}
+
void tst_StyleImports::attachedTypesAvailable_data()
{
QTest::addColumn<QString>("import");