From caa58954e0d7f1b5ac4b65d7e8cf9a9b87a5dae0 Mon Sep 17 00:00:00 2001 From: Thomas Hartmann Date: Thu, 18 Jan 2024 15:55:09 +0100 Subject: [PATCH] Allow linking of colors in the Palette section of a theme This allows entries like toolbarBackgroundColor=background_Muted. The code tries to resolve assignments until all colors are resolved or in the last step no new color has been resolved. Cycles are not resolved, but do not lead to issues. In case some colors are not resolved we use the original code to assign black and show an error message. This also add the possibility to include ini files like this: Includes="base.ini" Change-Id: I31124a59dffca45d14b81d528ba7c88220e57577 Reviewed-by: Qt CI Bot Reviewed-by: Alessandro Portale --- src/libs/utils/theme/theme.cpp | 112 +++++++++++++++++++++++++++------ src/libs/utils/theme/theme.h | 2 + src/libs/utils/theme/theme_p.h | 2 + 3 files changed, 98 insertions(+), 18 deletions(-) diff --git a/src/libs/utils/theme/theme.cpp b/src/libs/utils/theme/theme.cpp index 9b7afa71ebf..8800c85eb80 100644 --- a/src/libs/utils/theme/theme.cpp +++ b/src/libs/utils/theme/theme.cpp @@ -5,6 +5,7 @@ #include "theme_p.h" #include "../hostosinfo.h" #include "../qtcassert.h" +#include "filepath.h" #ifdef Q_OS_MACOS #import "theme_mac.h" #endif @@ -136,6 +137,21 @@ QString Theme::imageFile(Theme::ImageFile imageFile, const QString &fallBack) co return file.isEmpty() ? fallBack : file; } +QColor Theme::readNamedColorNoWarning(const QString &color) const +{ + const auto it = d->palette.constFind(color); + if (it != d->palette.constEnd()) + return it.value(); + if (color == QLatin1String("style")) + return {}; + + const QColor col('#' + color); + if (!col.isValid()) { + return {}; + } + return {col}; +} + QPair Theme::readNamedColor(const QString &color) const { const auto it = d->palette.constFind(color); @@ -167,39 +183,52 @@ void Theme::setDisplayName(const QString &name) d->displayName = name; } -void Theme::readSettings(QSettings &settings) +void Theme::readSettingsInternal(QSettings &settings) { - d->fileName = settings.fileName(); + const QStringList includes = settings.value("Includes").toString().split(",", Qt::SkipEmptyParts); + + for (const QString &include : includes) { + FilePath path = FilePath::fromString(d->fileName); + const Utils::FilePath includedPath = path.parentDir().pathAppended(include); + + if (includedPath.exists()) { + QSettings themeSettings(includedPath.toString(), QSettings::IniFormat); + readSettingsInternal(themeSettings); + } else { + qWarning("Theme \"%s\" misses include \"%s\".", + qPrintable(d->fileName), + qPrintable(includedPath.toUserOutput())); + } + } + const QMetaObject &m = *metaObject(); { - d->displayName = settings.value(QLatin1String("ThemeName"), QLatin1String("unnamed")).toString(); + d->displayName = settings.value(QLatin1String("ThemeName"), QLatin1String("unnamed")) + .toString(); d->preferredStyles = settings.value(QLatin1String("PreferredStyles")).toStringList(); d->preferredStyles.removeAll(QString()); - d->defaultTextEditorColorScheme = - settings.value(QLatin1String("DefaultTextEditorColorScheme")).toString(); + d->defaultTextEditorColorScheme + = settings.value(QLatin1String("DefaultTextEditorColorScheme")).toString(); d->enforceAccentColorOnMacOS = settings.value("EnforceAccentColorOnMacOS").toString(); } + { settings.beginGroup(QLatin1String("Palette")); const QStringList allKeys = settings.allKeys(); - for (const QString &key : allKeys) - d->palette[key] = readNamedColor(settings.value(key).toString()).first; + for (const QString &key : allKeys) { + d->unresolvedPalette[key] = settings.value(key).toString(); + } + settings.endGroup(); } { settings.beginGroup(QLatin1String("Colors")); - QMetaEnum e = m.enumerator(m.indexOfEnumerator("Color")); - for (int i = 0, total = e.keyCount(); i < total; ++i) { - const QString key = QLatin1String(e.key(i)); - if (!settings.contains(key)) { - if (i < PaletteWindow || i > PalettePlaceholderTextDisabled) - qWarning("Theme \"%s\" misses color setting for key \"%s\".", - qPrintable(d->fileName), qPrintable(key)); - continue; - } - d->colors[i] = readNamedColor(settings.value(key).toString()); + const QStringList allKeys = settings.allKeys(); + for (const QString &key : allKeys) { + d->unresolvedPalette[key] = settings.value(key).toString(); } + settings.endGroup(); } { @@ -216,13 +245,60 @@ void Theme::readSettings(QSettings &settings) QMetaEnum e = m.enumerator(m.indexOfEnumerator("Flag")); for (int i = 0, total = e.keyCount(); i < total; ++i) { const QString key = QLatin1String(e.key(i)); - QTC_ASSERT(settings.contains(key), return);; + QTC_ASSERT(settings.contains(key), return ); d->flags[i] = settings.value(key).toBool(); } settings.endGroup(); } } +void Theme::readSettings(QSettings &settings) +{ + d->fileName = settings.fileName(); + + readSettingsInternal(settings); + + int oldInvalidColors = 1; + int unresolvedColors = 0; + + const QStringList allKeys = d->unresolvedPalette.keys(); + do { + oldInvalidColors = unresolvedColors; + unresolvedColors = 0; + for (const QString &key : allKeys) { + const QColor currentColor = d->palette[key]; + if (currentColor.isValid()) + continue; + QColor color = readNamedColorNoWarning(d->unresolvedPalette.value(key)); + if (!color.isValid()) + ++unresolvedColors; + d->palette[key] = color; + } + + //If all colors are resolved or in the last step no new color has been resolved break. + } while (unresolvedColors > 0 && oldInvalidColors != unresolvedColors); + + if (unresolvedColors > 0) { //Show warnings for unresolved colors ad set them to black. + for (const QString &key : allKeys) + d->palette[key] = readNamedColor(d->unresolvedPalette.value(key)).first; + } + + const QMetaObject &m = *metaObject(); + + QMetaEnum e = m.enumerator(m.indexOfEnumerator("Color")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + if (!d->unresolvedPalette.contains(key)) { + if (i < PaletteWindow || i > PalettePlaceholderTextDisabled) + qWarning("Theme \"%s\" misses color setting for key \"%s\".", + qPrintable(d->fileName), + qPrintable(key)); + continue; + } + d->colors[i] = readNamedColor(d->unresolvedPalette.value(key)); + } +} + bool Theme::systemUsesDarkMode() { if (HostOsInfo::isWindowsHost()) { diff --git a/src/libs/utils/theme/theme.h b/src/libs/utils/theme/theme.h index 605c165024e..2e4d61d943b 100644 --- a/src/libs/utils/theme/theme.h +++ b/src/libs/utils/theme/theme.h @@ -579,8 +579,10 @@ protected: ThemePrivate *d; private: + void readSettingsInternal(QSettings &settings); friend QTCREATOR_UTILS_EXPORT Theme *creatorTheme(); friend QTCREATOR_UTILS_EXPORT Theme *proxyTheme(); + QColor readNamedColorNoWarning(const QString &color) const; QPair readNamedColor(const QString &color) const; }; diff --git a/src/libs/utils/theme/theme_p.h b/src/libs/utils/theme/theme_p.h index 14483f6d58c..4c751264401 100644 --- a/src/libs/utils/theme/theme_p.h +++ b/src/libs/utils/theme/theme_p.h @@ -27,6 +27,8 @@ public: QList imageFiles; QList flags; QMap palette; + QMap unresolvedPalette; + QMap unresolvedColors; }; QTCREATOR_UTILS_EXPORT void setCreatorTheme(Theme *theme);