Use json file based themes instead of code to create them (theme editor + theme mode settings)

This commit is contained in:
luisangelsm
2026-03-02 21:23:39 +01:00
parent 87fada611d
commit 547e48cc04
42 changed files with 2776 additions and 1145 deletions

View File

@ -1,14 +1,13 @@
#include "theme_manager.h"
#include "appearance_configuration.h"
#include "theme.h"
#include "theme_factory.h"
#include "theme_repository.h"
#include <QGuiApplication>
#include <QPalette>
#include <QStyleHints>
// TODO: add API to force color scheme //styleHints->setColorScheme(Qt::ColorScheme::Dark);
ThemeManager::ThemeManager()
{
}
@ -19,36 +18,106 @@ ThemeManager &ThemeManager::instance()
return instance;
}
void ThemeManager::initialize()
void ThemeManager::initialize(AppearanceConfiguration *config, ThemeRepository *repository)
{
this->config = config;
this->repository = repository;
auto *styleHints = qGuiApp->styleHints();
auto colorScheme = styleHints->colorScheme();
// Re-resolve when OS color scheme changes (relevant for FollowSystem mode)
connect(styleHints, &QStyleHints::colorSchemeChanged, this, &ThemeManager::resolveTheme, Qt::QueuedConnection);
// TODO: settings are needed to decide what theme to use
auto applyColorScheme = [this](Qt::ColorScheme scheme) {
setTheme(scheme == Qt::ColorScheme::Dark ? ThemeId::Dark : ThemeId::Light);
};
// Re-resolve when the user changes any theme setting
connect(config, &AppearanceConfiguration::selectionChanged, this, &ThemeManager::resolveTheme);
applyColorScheme(colorScheme);
connect(styleHints, &QStyleHints::colorSchemeChanged, this, applyColorScheme, Qt::QueuedConnection);
resolveTheme();
}
void ThemeManager::setTheme(ThemeId themeId)
void ThemeManager::setTheme(const Theme &theme)
{
if (this->themeId == themeId) {
return;
}
this->themeId = themeId;
updateCurrentTheme();
currentTheme = theme;
emit themeChanged();
}
void ThemeManager::updateCurrentTheme()
Theme ThemeManager::themeFromId(const QString &id, ThemeVariant fallbackVariant)
{
currentTheme = makeTheme(themeId);
// Try the repository first (handles both builtin and user themes via JSON)
if (repository && repository->contains(id)) {
QJsonObject json = repository->loadThemeJson(id);
if (!json.isEmpty())
return makeTheme(json);
}
// Fallback to the builtin that matches the current dark/light intent.
const QString fallbackId = (fallbackVariant == ThemeVariant::Dark)
? QStringLiteral("builtin/dark")
: QStringLiteral("builtin/light");
if (repository && repository->contains(fallbackId)) {
QJsonObject json = repository->loadThemeJson(fallbackId);
if (!json.isEmpty())
return makeTheme(json);
}
return {};
}
void ThemeManager::resolveTheme()
{
if (!config)
return;
const auto &sel = config->selection();
QString id;
ThemeVariant fallbackVariant;
switch (sel.mode) {
case ThemeMode::FollowSystem: {
const bool isDark = (qGuiApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark);
id = isDark ? sel.darkThemeId : sel.lightThemeId;
fallbackVariant = isDark ? ThemeVariant::Dark : ThemeVariant::Light;
break;
}
case ThemeMode::Light:
id = sel.lightThemeId;
fallbackVariant = ThemeVariant::Light;
break;
case ThemeMode::Dark:
id = sel.darkThemeId;
fallbackVariant = ThemeVariant::Dark;
break;
case ThemeMode::ForcedTheme:
id = sel.fixedThemeId;
fallbackVariant = (qGuiApp->styleHints()->colorScheme() == Qt::ColorScheme::Dark)
? ThemeVariant::Dark
: ThemeVariant::Light;
break;
}
const Theme theme = themeFromId(id, fallbackVariant);
// Sync Qt's application-level color scheme so native widgets (menus, scrollbars,
// standard dialogs) use the correct palette before themeChanged() is emitted.
#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
Qt::ColorScheme scheme;
switch (sel.mode) {
case ThemeMode::FollowSystem:
scheme = Qt::ColorScheme::Unknown; // delegate to OS
break;
case ThemeMode::Light:
scheme = Qt::ColorScheme::Light;
break;
case ThemeMode::Dark:
scheme = Qt::ColorScheme::Dark;
break;
case ThemeMode::ForcedTheme:
scheme = (theme.meta.variant == ThemeVariant::Dark)
? Qt::ColorScheme::Dark
: Qt::ColorScheme::Light;
break;
}
qGuiApp->styleHints()->setColorScheme(scheme);
#endif
setTheme(theme);
}