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 <qt_ci_bot@qt-project.org>
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
Thomas Hartmann
2024-01-18 15:55:09 +01:00
parent 46769e72e4
commit caa58954e0
3 changed files with 98 additions and 18 deletions

View File

@@ -5,6 +5,7 @@
#include "theme_p.h" #include "theme_p.h"
#include "../hostosinfo.h" #include "../hostosinfo.h"
#include "../qtcassert.h" #include "../qtcassert.h"
#include "filepath.h"
#ifdef Q_OS_MACOS #ifdef Q_OS_MACOS
#import "theme_mac.h" #import "theme_mac.h"
#endif #endif
@@ -136,6 +137,21 @@ QString Theme::imageFile(Theme::ImageFile imageFile, const QString &fallBack) co
return file.isEmpty() ? fallBack : file; 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<QColor, QString> Theme::readNamedColor(const QString &color) const QPair<QColor, QString> Theme::readNamedColor(const QString &color) const
{ {
const auto it = d->palette.constFind(color); const auto it = d->palette.constFind(color);
@@ -167,39 +183,52 @@ void Theme::setDisplayName(const QString &name)
d->displayName = 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(); 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 = settings.value(QLatin1String("PreferredStyles")).toStringList();
d->preferredStyles.removeAll(QString()); d->preferredStyles.removeAll(QString());
d->defaultTextEditorColorScheme = d->defaultTextEditorColorScheme
settings.value(QLatin1String("DefaultTextEditorColorScheme")).toString(); = settings.value(QLatin1String("DefaultTextEditorColorScheme")).toString();
d->enforceAccentColorOnMacOS = settings.value("EnforceAccentColorOnMacOS").toString(); d->enforceAccentColorOnMacOS = settings.value("EnforceAccentColorOnMacOS").toString();
} }
{ {
settings.beginGroup(QLatin1String("Palette")); settings.beginGroup(QLatin1String("Palette"));
const QStringList allKeys = settings.allKeys(); const QStringList allKeys = settings.allKeys();
for (const QString &key : allKeys) for (const QString &key : allKeys) {
d->palette[key] = readNamedColor(settings.value(key).toString()).first; d->unresolvedPalette[key] = settings.value(key).toString();
}
settings.endGroup(); settings.endGroup();
} }
{ {
settings.beginGroup(QLatin1String("Colors")); settings.beginGroup(QLatin1String("Colors"));
QMetaEnum e = m.enumerator(m.indexOfEnumerator("Color")); const QStringList allKeys = settings.allKeys();
for (int i = 0, total = e.keyCount(); i < total; ++i) { for (const QString &key : allKeys) {
const QString key = QLatin1String(e.key(i)); d->unresolvedPalette[key] = settings.value(key).toString();
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());
} }
settings.endGroup(); settings.endGroup();
} }
{ {
@@ -216,13 +245,60 @@ void Theme::readSettings(QSettings &settings)
QMetaEnum e = m.enumerator(m.indexOfEnumerator("Flag")); QMetaEnum e = m.enumerator(m.indexOfEnumerator("Flag"));
for (int i = 0, total = e.keyCount(); i < total; ++i) { for (int i = 0, total = e.keyCount(); i < total; ++i) {
const QString key = QLatin1String(e.key(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(); d->flags[i] = settings.value(key).toBool();
} }
settings.endGroup(); 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() bool Theme::systemUsesDarkMode()
{ {
if (HostOsInfo::isWindowsHost()) { if (HostOsInfo::isWindowsHost()) {

View File

@@ -579,8 +579,10 @@ protected:
ThemePrivate *d; ThemePrivate *d;
private: private:
void readSettingsInternal(QSettings &settings);
friend QTCREATOR_UTILS_EXPORT Theme *creatorTheme(); friend QTCREATOR_UTILS_EXPORT Theme *creatorTheme();
friend QTCREATOR_UTILS_EXPORT Theme *proxyTheme(); friend QTCREATOR_UTILS_EXPORT Theme *proxyTheme();
QColor readNamedColorNoWarning(const QString &color) const;
QPair<QColor, QString> readNamedColor(const QString &color) const; QPair<QColor, QString> readNamedColor(const QString &color) const;
}; };

View File

@@ -27,6 +27,8 @@ public:
QList<QString> imageFiles; QList<QString> imageFiles;
QList<bool> flags; QList<bool> flags;
QMap<QString, QColor> palette; QMap<QString, QColor> palette;
QMap<QString, QString> unresolvedPalette;
QMap<QString, QString> unresolvedColors;
}; };
QTCREATOR_UTILS_EXPORT void setCreatorTheme(Theme *theme); QTCREATOR_UTILS_EXPORT void setCreatorTheme(Theme *theme);