diff --git a/cockatrice/src/interface/palette_editor/palette_editor_dialog.cpp b/cockatrice/src/interface/palette_editor/palette_editor_dialog.cpp index 9cde72c01..dc1e96901 100644 --- a/cockatrice/src/interface/palette_editor/palette_editor_dialog.cpp +++ b/cockatrice/src/interface/palette_editor/palette_editor_dialog.cpp @@ -297,7 +297,7 @@ void PaletteEditorDialog::onSave() if (it.key() == loadedScheme) { continue; } - if (it.value().colors == savedConfig.value(it.key()).colors) { + if (it.value() == savedConfig.value(it.key())) { continue; } if (!ThemeManager::commitPalette(saveDir, it.key(), it.value())) { @@ -308,7 +308,7 @@ void PaletteEditorDialog::onSave() } // Commit the active scheme last so the global colour scheme matches. - if (workingConfig[loadedScheme].colors != savedConfig.value(loadedScheme).colors) { + if (workingConfig[loadedScheme] != savedConfig.value(loadedScheme)) { if (!ThemeManager::commitPalette(saveDir, loadedScheme, workingConfig[loadedScheme])) { QMessageBox::warning(this, tr("Save failed"), tr("Could not write %1 to:\n%2").arg(PaletteConfig::fileName(loadedScheme), saveDir)); diff --git a/cockatrice/src/interface/palette_editor/palette_grid_widget.cpp b/cockatrice/src/interface/palette_editor/palette_grid_widget.cpp index f66ef1032..97d28b731 100644 --- a/cockatrice/src/interface/palette_editor/palette_grid_widget.cpp +++ b/cockatrice/src/interface/palette_editor/palette_grid_widget.cpp @@ -49,7 +49,7 @@ static const QMap ROLE_DESCRIPTIONS = { static const QMap APP_ROLE_DESCRIPTIONS = { {AppColor::AccentStrong, QT_TR_NOOP("Vivid primary accent (e.g. home-tab button gradient start)")}, - {AppColor::AccentSoft, QT_TR_NOOP("Lighted, desaturated accent (e.g. home-tab button gradient end)")}, + {AppColor::AccentSoft, QT_TR_NOOP("Lightened, desaturated accent (e.g. home-tab button gradient end)")}, }; PaletteGridWidget::PaletteGridWidget(QWidget *parent) : QWidget(parent) @@ -144,9 +144,10 @@ void PaletteGridWidget::buildGrid(QWidget *host) appHeader->setAutoFillBackground(true); appHeader->setContentsMargins(4, 4, 4, 4); grid->addWidget(appHeader, appHeaderRow, 0, 1, 4); + headerLabels.append(appHeader); for (int i = 0; i < appEnum.keyCount(); ++i) { - auto role = static_cast(i); + auto role = static_cast(appEnum.value(i)); const int row = appHeaderRow + 1 + i; if (i % 2 == 0) { @@ -215,7 +216,7 @@ void PaletteGridWidget::loadPalette(const PaletteConfig &cfg) QMetaEnum appEnum = QMetaEnum::fromType(); for (int i = 0; i < appEnum.keyCount(); ++i) { - auto role = static_cast(i); + auto role = static_cast(appEnum.value(i)); QColor color = cfg.appColors.value(role); if (!color.isValid()) { color = themeManager->appColor(role); @@ -235,7 +236,7 @@ PaletteConfig PaletteGridWidget::currentPaletteConfig() const QMetaEnum appEnum = QMetaEnum::fromType(); for (int i = 0; i < appEnum.keyCount(); ++i) { - auto role = static_cast(i); + auto role = static_cast(appEnum.value(i)); cfg.appColors[role] = appColorButtons[role]->getColor(); } diff --git a/cockatrice/src/interface/theme_config.cpp b/cockatrice/src/interface/theme_config.cpp index 8de2fe6b9..4420eefe1 100644 --- a/cockatrice/src/interface/theme_config.cpp +++ b/cockatrice/src/interface/theme_config.cpp @@ -96,7 +96,7 @@ bool ThemeConfig::save(const QString &themeDirPath) const bool PaletteConfig::hasPalette() const { - return !colors.isEmpty(); + return !colors.isEmpty() || !appColors.isEmpty(); } QString PaletteConfig::toToml() const diff --git a/cockatrice/src/interface/theme_config.h b/cockatrice/src/interface/theme_config.h index 08978d1f7..567aeccda 100644 --- a/cockatrice/src/interface/theme_config.h +++ b/cockatrice/src/interface/theme_config.h @@ -39,6 +39,14 @@ struct PaletteConfig QMap> colors; QMap appColors; + bool operator==(const PaletteConfig &rhs) const + { + return colors == rhs.colors && appColors == rhs.appColors; + } + bool operator!=(const PaletteConfig &rhs) const + { + return !(*this == rhs); + } bool hasPalette() const; QString toToml() const; diff --git a/cockatrice/src/interface/theme_manager.cpp b/cockatrice/src/interface/theme_manager.cpp index a0fa8370e..d1bccbc0b 100644 --- a/cockatrice/src/interface/theme_manager.cpp +++ b/cockatrice/src/interface/theme_manager.cpp @@ -441,14 +441,12 @@ QColor ThemeManager::appColor(AppColor::Role role) const return it.value(); } - // QPalette::Accent was introduced in Qt 6.6; before that the nearest - // accent is the selection highlight, which Accent defaults to when unset. - const QColor accent = qApp->palette().color(QPalette::Active, -#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) - QPalette::Accent); -#else - QPalette::Highlight); -#endif + // QPalette::Accent was introduced in Qt 6.6 and several shipped palettes + // set it to a value barely distinguishable from Window, so it is not a + // reliable accent source. The selection highlight is the stable accent + // (Accent defaults to Highlight when unset), and deriving from it + // unconditionally keeps every Qt version rendering identically. + const QColor accent = qApp->palette().color(QPalette::Active, QPalette::Highlight); if (role == AppColor::AccentSoft) { constexpr int SOFT_SATURATION_PERCENT = 70; @@ -497,8 +495,19 @@ void ThemeManager::themeChangedSlot() // ── Load palette: custom first, then theme default ──────────────────── PaletteConfig palette = PaletteConfig::fromScheme(dirPath, activeScheme); - if (!palette.hasPalette()) { - palette = ThemeManager::loadDefaultPaletteConfig(dirPath, themeName, activeScheme); + const PaletteConfig themeDefault = ThemeManager::loadDefaultPaletteConfig(dirPath, themeName, activeScheme); + if (palette.hasPalette()) { + // A custom palette written before [AppColors] existed carries no app + // colors; merge the theme's shipped defaults so the identity colors + // survive (hasPalette() counts an app-colors-only file as a palette, + // so those are kept wholesale and never reach here empty). + for (auto it = themeDefault.appColors.cbegin(); it != themeDefault.appColors.cend(); ++it) { + if (!palette.appColors.contains(it.key())) { + palette.appColors.insert(it.key(), it.value()); + } + } + } else { + palette = themeDefault; } applyStyleAndPalette(themeName, themeCfg, palette, activeScheme); diff --git a/cockatrice/src/interface/widgets/general/home_widget.cpp b/cockatrice/src/interface/widgets/general/home_widget.cpp index 299340580..0f96dcd52 100644 --- a/cockatrice/src/interface/widgets/general/home_widget.cpp +++ b/cockatrice/src/interface/widgets/general/home_widget.cpp @@ -124,10 +124,13 @@ QPair HomeWidget::determineButtonColor() const switch (colorSource) { case HomeTabButtonColor::Automatic: { - if (usesThemeBackground()) { - // Static theme background: follow the theme's accent colors. + if (usesThemeBackground() && themeManager->isBuiltInTheme()) { + // Built-in themes paint a static theme background; follow the + // theme's identity accent colors rather than sampling the image. return paletteDerivedButtonColors(); } else { + // Non-built-in themes may ship their own background art, so + // extract the button colors from the image actually painted. return extractDominantColors(background); } } diff --git a/cockatrice/themes/Default/palette-default-light.toml b/cockatrice/themes/Default/palette-default-light.toml new file mode 100644 index 000000000..14c215cdf --- /dev/null +++ b/cockatrice/themes/Default/palette-default-light.toml @@ -0,0 +1,67 @@ +[Palette] +WindowText = #ff000000 +Button = #fff0f0f0 +Light = #ffffffff +Midlight = #ffe3e3e3 +Dark = #ffa0a0a0 +Mid = #ffa0a0a0 +Text = #ff000000 +BrightText = #ffffffff +ButtonText = #ff000000 +Base = #ffffffff +Window = #fff0f0f0 +Shadow = #ff696969 +HighlightedText = #ffffffff +Link = #ff0d5f28 +LinkVisited = #ff08401b +AlternateBase = #ffe9e7e3 +ToolTipBase = #ffffffdc +ToolTipText = #ff000000 +PlaceholderText = #80000000 + +[Palette.Disabled] +WindowText = #ff787878 +Button = #fff0f0f0 +Light = #ffffffff +Midlight = #fff7f7f7 +Dark = #ffa0a0a0 +Mid = #ffa0a0a0 +Text = #ff787878 +BrightText = #ffffffff +ButtonText = #ff787878 +Base = #fff0f0f0 +Window = #fff0f0f0 +Shadow = #ff000000 +HighlightedText = #ffffffff +Link = #ff0000ff +LinkVisited = #ffff00ff +AlternateBase = #fff7f7f7 +ToolTipBase = #ffffffdc +ToolTipText = #ff000000 +PlaceholderText = #80000000 + +[Palette.Inactive] +WindowText = #ff000000 +Button = #fff0f0f0 +Light = #ffffffff +Midlight = #ffe3e3e3 +Dark = #ffa0a0a0 +Mid = #ffa0a0a0 +Text = #ff000000 +BrightText = #ffffffff +ButtonText = #ff000000 +Base = #ffffffff +Window = #fff0f0f0 +Shadow = #ff696969 +HighlightedText = #ff000000 +Link = #ff0d5f28 +LinkVisited = #ff08401b +AlternateBase = #ffe9e7e3 +ToolTipBase = #ffffffdc +ToolTipText = #ff000000 +PlaceholderText = #80000000 + + +[AppColors] +AccentStrong = #ff148c3c +AccentSoft = #ff78c850 \ No newline at end of file