diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index 4263fc6e2..63ccc4e9c 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -403,7 +403,6 @@ set(cockatrice_SOURCES src/interface/widgets/tabs/api/commander_spellbook/commander_bracket_widget.cpp src/interface/widgets/tabs/api/commander_spellbook/handle_commander_brackets.cpp src/interface/widgets/onboarding/banner_shader_config.h - src/interface/widgets/onboarding/brand_colors.h src/interface/widgets/onboarding/first_run_wizard.cpp src/interface/widgets/onboarding/first_run_wizard.h src/interface/widgets/onboarding/first_run_wizard_page.cpp @@ -531,7 +530,6 @@ qt6_add_shaders( "src/interface/widgets/onboarding/shaders" FILES src/interface/widgets/onboarding/shaders/brand_banner.frag - src/interface/widgets/onboarding/shaders/brand_plate.frag ) qt6_add_resources( diff --git a/cockatrice/src/interface/widgets/general/home_widget.cpp b/cockatrice/src/interface/widgets/general/home_widget.cpp index 648d315f9..79544c5a8 100644 --- a/cockatrice/src/interface/widgets/general/home_widget.cpp +++ b/cockatrice/src/interface/widgets/general/home_widget.cpp @@ -11,8 +11,6 @@ #include "home_tab_button_color.h" #include -#include -#include #include #include #include @@ -23,7 +21,8 @@ #include HomeWidget::HomeWidget(QWidget *parent, TabSupervisor *_tabSupervisor) - : QWidget(parent), tabSupervisor(_tabSupervisor), background(themePixmap(QStringLiteral("backgrounds/home"))) + : QWidget(parent), tabSupervisor(_tabSupervisor), background(themePixmap(QStringLiteral("backgrounds/home"))), + overlay(themePixmap(QStringLiteral("cockatrice"))) { layout = new QGridLayout(this); @@ -65,17 +64,12 @@ HomeWidget::HomeWidget(QWidget *parent, TabSupervisor *_tabSupervisor) // not on SettingsCache::themeChanged, so re-resolve the variant background. connect(themeManager, &ThemeManager::themeChanged, this, &HomeWidget::initializeBackgroundFromSource); connect(themeManager, &ThemeManager::paletteChanged, this, &HomeWidget::updateButtonsToBackgroundColor); - connect(themeManager, &ThemeManager::paletteChanged, this, &HomeWidget::updateLogoOverlay); connect(&SettingsCache::instance().appearance(), &AppearanceSettings::homeTabButtonColorChanged, this, &HomeWidget::updateButtonsToBackgroundColor); } void HomeWidget::initializeBackgroundFromSource() { - // The featured logo is theme/scheme-derived too; reload it alongside the - // background so a theme or appearance switch doesn't leave it stale. - updateLogoOverlay(); - if (CardDatabaseManager::getInstance()->getLoadStatus() != LoadStatus::Ok) { connect(CardDatabaseManager::getInstance(), &CardDatabase::cardDatabaseLoadingFinished, this, &HomeWidget::initializeBackgroundFromSource); @@ -235,10 +229,10 @@ QGroupBox *HomeWidget::createButtons() QVBoxLayout *boxLayout = new QVBoxLayout; boxLayout->setAlignment(Qt::AlignHCenter); - logoLabel = new QLabel; + QLabel *logoLabel = new QLabel; + logoLabel->setPixmap(overlay.scaledToWidth(200, Qt::SmoothTransformation)); logoLabel->setAlignment(Qt::AlignCenter); boxLayout->addWidget(logoLabel); - updateLogoOverlay(); boxLayout->addSpacing(25); connectButton = new HomeStyledButton("Connect/Play", gradientColors); @@ -439,56 +433,3 @@ void HomeWidget::paintEvent(QPaintEvent *event) QWidget::paintEvent(event); } - -void HomeWidget::updateLogoOverlay() -{ - // Emulate cockatrice.svg in Qt rather than rendering the baked-in SVG. - // The SVG has no separate plate: the gradient fills the bird's silhouette - // paths (light #c9fd62/AccentSoft at the top-left, dark #139740/AccentStrong - // toward the bottom-right — the SVG's linearGradient4265-7-8 stops along - // its userSpaceOnUse axis), and the white highlight path - // (cockatrice-logo-white) sits on top. So we paint that gradient clipped to - // the full logo silhouette (the full-color logo's alpha), then overlay the - // white mark. Colours stay fully theme-driven and independent of the static - // greens baked into the SVG. - const QColor strong = themeManager->appColor(AppColor::AccentStrong); - const QColor soft = themeManager->appColor(AppColor::AccentSoft); - - const QPixmap silhouette = themePixmap(QStringLiteral("cockatrice")).scaledToWidth(200, Qt::SmoothTransformation); - const QPixmap whiteMark = - themePixmap(QStringLiteral("cockatrice-logo-white")).scaledToWidth(200, Qt::SmoothTransformation); - if (silhouette.isNull() || whiteMark.isNull()) { - return; - } - - QPixmap composite(silhouette.size()); - composite.fill(Qt::transparent); - - { - QPainter painter(&composite); - painter.setRenderHint(QPainter::Antialiasing); - painter.setRenderHint(QPainter::SmoothPixmapTransform); - - // Recreate cockatrice.svg's own gradient geometry (linearGradient - // 4265-7-8, userSpaceOnUse): light AccentSoft at S=(-8.097,-97.746), - // dark AccentStrong at E=(162.455,295.208), on the SVG's 300x300 - // canvas. Scale those coordinates to this composite's size. - const qreal scale = composite.width() / 300.0; - QLinearGradient gradient(QPointF(-8.097, -97.746) * scale, QPointF(162.455, 295.208) * scale); - gradient.setColorAt(0.0, soft); - gradient.setColorAt(1.0, strong); - painter.fillRect(composite.rect(), gradient); - - // Clip the gradient to the full logo silhouette exactly as the SVG's - // gradient paths are confined to the bird. - painter.setCompositionMode(QPainter::CompositionMode_DestinationIn); - painter.drawPixmap(0, 0, silhouette); - - painter.setCompositionMode(QPainter::CompositionMode_SourceOver); - painter.drawPixmap(0, 0, whiteMark); - } - - if (logoLabel) { - logoLabel->setPixmap(composite); - } -} diff --git a/cockatrice/src/interface/widgets/general/home_widget.h b/cockatrice/src/interface/widgets/general/home_widget.h index 1cadc4a67..9df0d7b6a 100644 --- a/cockatrice/src/interface/widgets/general/home_widget.h +++ b/cockatrice/src/interface/widgets/general/home_widget.h @@ -15,9 +15,6 @@ #include #include -class QGridLayout; -class QLabel; - class HomeWidget : public QWidget { @@ -44,14 +41,13 @@ private: QPixmap background; CardInfoPictureArtCropWidget *backgroundSourceCard = nullptr; DeckList backgroundSourceDeck; - QLabel *logoLabel = nullptr; + QPixmap overlay; QPair gradientColors; HomeStyledButton *connectButton; void setRandomCard(ExactCard &newCard); void loadBackgroundSourceDeck(); QPair determineButtonColor() const; - void updateLogoOverlay(); }; #endif // HOME_WIDGET_H diff --git a/cockatrice/src/interface/widgets/onboarding/banner_shader_config.h b/cockatrice/src/interface/widgets/onboarding/banner_shader_config.h index 6008044ff..32f3e89c0 100644 --- a/cockatrice/src/interface/widgets/onboarding/banner_shader_config.h +++ b/cockatrice/src/interface/widgets/onboarding/banner_shader_config.h @@ -38,10 +38,6 @@ class BannerShaderConfig : public QObject Q_PROPERTY(QColor colorA READ colorA WRITE setColorA NOTIFY colorAChanged) Q_PROPERTY(QColor colorB READ colorB WRITE setColorB NOTIFY colorBChanged) Q_PROPERTY(QColor accent READ accent WRITE setAccent NOTIFY accentChanged) - Q_PROPERTY(QColor glowColor READ glowColor WRITE setGlowColor NOTIFY glowColorChanged) - Q_PROPERTY(QColor brandStrong READ brandStrong WRITE setBrandStrong NOTIFY brandStrongChanged) - Q_PROPERTY(QColor brandSoft READ brandSoft WRITE setBrandSoft NOTIFY brandSoftChanged) - Q_PROPERTY(qreal vignetteMin READ vignetteMin WRITE setVignetteMin NOTIFY vignetteMinChanged) Q_PROPERTY(bool logoVisible READ logoVisible WRITE setLogoVisible NOTIFY logoVisibleChanged) Q_PROPERTY(qreal logoGlow READ logoGlow WRITE setLogoGlow NOTIFY logoGlowChanged) @@ -189,54 +185,6 @@ public: } } - QColor glowColor() const - { - return m_glowColor; - } - void setGlowColor(const QColor &c) - { - if (c != m_glowColor) { - m_glowColor = c; - emit glowColorChanged(); - } - } - - QColor brandStrong() const - { - return m_brandStrong; - } - void setBrandStrong(const QColor &c) - { - if (c != m_brandStrong) { - m_brandStrong = c; - emit brandStrongChanged(); - } - } - - QColor brandSoft() const - { - return m_brandSoft; - } - void setBrandSoft(const QColor &c) - { - if (c != m_brandSoft) { - m_brandSoft = c; - emit brandSoftChanged(); - } - } - - qreal vignetteMin() const - { - return m_vignetteMin; - } - void setVignetteMin(qreal v) - { - if (v != m_vignetteMin) { - m_vignetteMin = v; - emit vignetteMinChanged(); - } - } - bool logoVisible() const { return m_logoVisible; @@ -274,10 +222,6 @@ signals: void colorAChanged(); void colorBChanged(); void accentChanged(); - void glowColorChanged(); - void brandStrongChanged(); - void brandSoftChanged(); - void vignetteMinChanged(); void logoVisibleChanged(); void logoGlowChanged(); @@ -295,16 +239,9 @@ private: bool m_frontIsA = true; - // Curated fallback seed values -- BannerHost overwrites these with - // palette-derived colours (see shader_banner_widget.cpp) before the first - // paint, so they only matter as a safe pre-first-apply default. QColor m_colorA{0x1A, 0x1A, 0x20}; QColor m_colorB{0x0E, 0x0E, 0x12}; QColor m_accent{0x8B, 0xDD, 0x6B}; - QColor m_glowColor{Qt::white}; - QColor m_brandStrong{0x13, 0x97, 0x40}; - QColor m_brandSoft{0xC9, 0xFD, 0x62}; - qreal m_vignetteMin = 0.62; bool m_logoVisible = false; qreal m_logoGlow = 1.0; diff --git a/cockatrice/src/interface/widgets/onboarding/brand_colors.h b/cockatrice/src/interface/widgets/onboarding/brand_colors.h deleted file mode 100644 index bf173270b..000000000 --- a/cockatrice/src/interface/widgets/onboarding/brand_colors.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef BRAND_COLORS_H -#define BRAND_COLORS_H - -#include - -/** @brief Cockatrice brand green. - * - * Single source of truth for the onboarding brand accent: it backs the - * banner's shader-accent uniform as the curated fallback when the active - * palette resolves no usable Highlight, and it preseads the wizard's - * QuickSetupPanel so a freshly generated palette keeps the brand identity - * until the user picks their own look. */ -inline const QColor kCockatriceBrandGreen(0x8B, 0xDD, 0x6B); - -#endif // BRAND_COLORS_H \ No newline at end of file diff --git a/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.cpp b/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.cpp index 797fe4425..3293b19ac 100644 --- a/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.cpp +++ b/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.cpp @@ -14,31 +14,10 @@ #include #include #include -#include #include #include #include -namespace -{ -/** @brief A theme's shipped identity accent, immune to any user- or auto- - * generated palette that may currently be masking appColor(). */ -QColor themeIdentityAccent(const QString &themeDirPath, const QString &themeName) -{ - for (const QString &scheme : {QStringLiteral("Light"), QStringLiteral("Dark")}) { - const PaletteConfig cfg = ThemeManager::loadDefaultPaletteConfig(themeDirPath, themeName, scheme); - if (cfg.appColors.contains(AppColor::AccentStrong)) { - return cfg.appColors.value(AppColor::AccentStrong); - } - const QColor highlight = cfg.colors.value(QPalette::Active).value(QPalette::Highlight); - if (highlight.isValid()) { - return highlight; - } - } - return {}; -} -} // namespace - ThemeSetupPage::ThemeSetupPage(QWidget *parent) : FirstRunWizardPage(parent) { themeCombo = new QComboBox(this); @@ -51,15 +30,6 @@ ThemeSetupPage::ThemeSetupPage(QWidget *parent) : FirstRunWizardPage(parent) quickSetupPanel = new QuickSetupPanel(this); - // Seed the picker from the current theme's own identity accent rather than - // a hardcoded brand green: Plasma seeds violet, Fusion green, etc., and it - // is immune to stale generated palettes that may mask appColor(). This was - // initially a brand-green workaround from before Fusion became the default. - // setAccentColor blocks signals, so this never triggers a generation. - lastSeededTheme = SettingsCache::instance().getThemeName(); - quickSetupPanel->setAccentColor( - themeIdentityAccent(themeManager->getAvailableThemes().value(lastSeededTheme), lastSeededTheme)); - connect(themeCombo, QOverload::of(&QComboBox::currentIndexChanged), this, &ThemeSetupPage::onThemeChanged); connect(schemeCombo, QOverload::of(&QComboBox::currentIndexChanged), this, &ThemeSetupPage::onSchemeChanged); connect(quickSetupPanel, &QuickSetupPanel::valueChanged, this, &ThemeSetupPage::onGenerateFromAccent); @@ -77,8 +47,7 @@ ThemeSetupPage::ThemeSetupPage(QWidget *parent) : FirstRunWizardPage(parent) // Mirrors AppearanceSettingsPage's identical listener for the combo-sync // half of this. connect(themeManager, &ThemeManager::themeChanged, this, [this] { - const QString newTheme = SettingsCache::instance().getThemeName(); - const QString newDir = themeManager->getAvailableThemes().value(newTheme); + const QString newDir = themeManager->getAvailableThemes().value(SettingsCache::instance().getThemeName()); const ThemeConfig cfg = ThemeConfig::fromThemeDir(newDir); const QString current = cfg.colorScheme; @@ -87,14 +56,6 @@ ThemeSetupPage::ThemeSetupPage(QWidget *parent) : FirstRunWizardPage(parent) schemeCombo->setCurrentIndex(idx >= 0 ? idx : 0); schemeCombo->blockSignals(false); - // Keep the picker's accent in step with the theme's own identity; the - // swatch seeded at construction would otherwise stay stale (e.g. green - // from a previous theme) when the user toggles themes. - if (newTheme != lastSeededTheme) { - lastSeededTheme = newTheme; - quickSetupPanel->setAccentColor(themeIdentityAccent(newDir, newTheme)); - } - maybeAutoGeneratePalette(); }); @@ -197,14 +158,8 @@ void ThemeSetupPage::maybeAutoGeneratePalette() const QString dirPath = themeManager->getAvailableThemes().value(SettingsCache::instance().getThemeName()); const QString scheme = resolvedScheme(); - // The theme dir may resolve to the user profile even for built-in themes - // (getAvailableThemes gives the user copy precedence), so consult the - // shipped palette too -- both via loadDefaultPaletteConfig's system fallback. - // Without it, scheme flips regenerate a fresh palette from the picker accent - // and clobber the curated colours the theme explicitly ships. if (PaletteConfig::fromScheme(dirPath, scheme).hasPalette() || - ThemeManager::loadDefaultPaletteConfig(dirPath, SettingsCache::instance().getThemeName(), scheme) - .hasPalette()) { + PaletteConfig::fromDefault(dirPath, scheme).hasPalette()) { return; // theme already has something real to show -- leave it alone } diff --git a/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.h b/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.h index 16a3c9a5d..d1f84c1b9 100644 --- a/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.h +++ b/cockatrice/src/interface/widgets/onboarding/pages/theme_setup_page.h @@ -53,9 +53,6 @@ private: QComboBox *homeTabBackgroundCombo; bool paletteDirty = false; - - /// Theme whose identity accent currently seeds the picker. - QString lastSeededTheme; }; #endif // THEME_SETUP_PAGE_H diff --git a/cockatrice/src/interface/widgets/onboarding/qml/BrandBanner.qml b/cockatrice/src/interface/widgets/onboarding/qml/BrandBanner.qml index d94e15280..f1a385cad 100644 --- a/cockatrice/src/interface/widgets/onboarding/qml/BrandBanner.qml +++ b/cockatrice/src/interface/widgets/onboarding/qml/BrandBanner.qml @@ -16,8 +16,6 @@ Item { property vector4d uColorA: Qt.vector4d(bannerConfig.colorA.r, bannerConfig.colorA.g, bannerConfig.colorA.b, 1.0) property vector4d uColorB: Qt.vector4d(bannerConfig.colorB.r, bannerConfig.colorB.g, bannerConfig.colorB.b, 1.0) property vector4d uAccent: Qt.vector4d(bannerConfig.accent.r, bannerConfig.accent.g, bannerConfig.accent.b, 1.0) - property vector4d uGlowColor: Qt.vector4d(bannerConfig.glowColor.r, bannerConfig.glowColor.g, bannerConfig.glowColor.b, 1.0) - property real uVignetteMin: bannerConfig.vignetteMin property real uLogoGlow: bannerConfig.logoGlow fragmentShader: "qrc:/onboarding/shaders/brand_banner.frag.qsb" } @@ -35,62 +33,30 @@ Item { property vector4d uColorA: Qt.vector4d(bannerConfig.colorA.r, bannerConfig.colorA.g, bannerConfig.colorA.b, 1.0) property vector4d uColorB: Qt.vector4d(bannerConfig.colorB.r, bannerConfig.colorB.g, bannerConfig.colorB.b, 1.0) property vector4d uAccent: Qt.vector4d(bannerConfig.accent.r, bannerConfig.accent.g, bannerConfig.accent.b, 1.0) - property vector4d uGlowColor: Qt.vector4d(bannerConfig.glowColor.r, bannerConfig.glowColor.g, bannerConfig.glowColor.b, 1.0) - property real uVignetteMin: bannerConfig.vignetteMin property real uLogoGlow: bannerConfig.logoGlow fragmentShader: "qrc:/onboarding/shaders/brand_banner.frag.qsb" } - // The white logo sits at full opacity on top of the static gradient plate — - // no glow, no breathing. The plate matches home_widget's QPainter composite. - Item { - id: logoHost - visible: bannerConfig.logoVisible + // The hero logo itself — breathes cleanly over a 0.5–1.0 opacity range + Image { + id: logo anchors.centerIn: parent + visible: bannerConfig.logoVisible + source: "qrc:/resources/cockatrice-logo-white.svg" width: root.height * 0.6 - height: width + height: width * (sourceSize.height > 0 ? sourceSize.height / Math.max(sourceSize.width, 1) : 1) + fillMode: Image.PreserveAspectFit + smooth: true + opacity: 0.5 + 0.5 * bannerConfig.logoGlow + sourceSize: Qt.size(256, 256) - // The full-color logo renders beneath the white mark and is consumed as - // a texture (layer.enabled) by the plate shader's silhouette mask, so - // the gradient is clipped to the bird exactly as the SVG's gradient - // paths are. It is never drawn to the screen itself. - Image { - id: silhouetteMask - anchors.fill: parent - source: "qrc:/resources/cockatrice.svg" - sourceSize: Qt.size(256, 256) - fillMode: Image.PreserveAspectFit - smooth: true - visible: false - layer.enabled: true - layer.smooth: true - } + Behavior on opacity { NumberAnimation { duration: 300; easing.type: Easing.InOutSine } } - // The logo's gradient plate, drawn behind the mark: a linear - // AccentSoft (light) -> AccentStrong (dark) sheet along the same - // top-left -> bottom-right userSpaceOnUse axis the baked-in SVG used, - // clipped to the bird silhouette via uSilhouette. The white highlight - // path above is theme independent. Sized to the logo itself — no - // rounded badge, matching home_widget's QPainter composite. Static. - // Small ShaderEffect, Qt 6.4-safe. - ShaderEffect { - id: brandPlate - anchors.fill: parent - property vector4d uStrong: Qt.vector4d(bannerConfig.brandStrong.r, bannerConfig.brandStrong.g, - bannerConfig.brandStrong.b, 1.0) - property vector4d uSoft: Qt.vector4d(bannerConfig.brandSoft.r, bannerConfig.brandSoft.g, - bannerConfig.brandSoft.b, 1.0) - property var uSilhouette: silhouetteMask - fragmentShader: "qrc:/onboarding/shaders/brand_plate.frag.qsb" - } - - Image { - id: logoImage - anchors.fill: parent - source: "qrc:/resources/cockatrice-logo-white.svg" - sourceSize: Qt.size(256, 256) - fillMode: Image.PreserveAspectFit - smooth: true + transform: Scale { + origin.x: logo.width / 2 + origin.y: logo.height / 2 + xScale: 0.94 + 0.06 * bannerConfig.logoGlow + yScale: 0.94 + 0.06 * bannerConfig.logoGlow } } -} \ No newline at end of file +} diff --git a/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.cpp b/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.cpp index 0b9f65783..fd1fb2a98 100644 --- a/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.cpp +++ b/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.cpp @@ -1,10 +1,7 @@ #include "shader_banner_widget.h" -#include "../../theme_manager.h" #include "banner_shader_config.h" -#include "brand_colors.h" -#include #include #include #include @@ -14,98 +11,11 @@ namespace { -// Curated near-black stage -- used only when the active palette resolves no -// usable window colour. Matches the banner's original design (dark and quiet -// so the accent stands out) and satisfies design-plans §2.1's "identity -// survives a bare palette". -constexpr QRgb kFallbackColorA = 0x1A1A20; -constexpr QRgb kFallbackColorB = 0x0E0E12; - -struct SuggestedColors -{ - QColor colorA; - QColor colorB; - QColor accent; - QColor glowColor; - QColor brandStrong; - QColor brandSoft; - qreal vignetteMin = 0.62; -}; - -SuggestedColors suggestedBannerColors() -{ - const QPalette &pal = qApp->palette(); - const QColor window = pal.color(QPalette::Active, QPalette::Window); - // Identity accent: the theme's [AppColors] AccentStrong, which appColor() - // resolves to QPalette::Highlight when a theme doesn't pin AccentStrong. - // Reading bare Highlight ignored curated accent tokens (Plasma's violet - // vs Default's green) whenever a palette didn't set the role itself. - const QColor accentStrong = themeManager->appColor(AppColor::AccentStrong); - if (!window.isValid() || !accentStrong.isValid()) { - return {QColor(kFallbackColorA), - QColor(kFallbackColorB), - kCockatriceBrandGreen, - QColor(Qt::white), - kCockatriceBrandGreen, - QColor(0xC9, 0xFD, 0x62), - 0.62}; - } - - // The theme's brand pair: AccentStrong is the deep green, AccentSoft the - // lime. These two appColors form the logo's "surrounding gradient" (deep - // core grading out to the soft, brand-toned glow) on both the banner and - // the home screen. - const QColor brandStrong = accentStrong; - const QColor brandSoft = themeManager->appColor(AppColor::AccentSoft); - - // Dress the stage for the scheme so the banner never fights the - // surrounding window in either mode. Dark palettes keep the original - // quiet near-black stage (lightness 29 → 16) with the theme's window - // hue; light palettes get a pastel "frosted accent" treatment built from - // the accent hue instead of a plain near-white copy: a coloured wash that - // clearly belongs to the theme. - const qreal luma = 0.299 * window.red() + 0.587 * window.green() + 0.114 * window.blue(); - const bool lightStage = luma > 115.0; - if (lightStage) { - const int hue = accentStrong.hslHue(); - // Achromatic accents (grey) get a neutral near-white stage instead. - const int stageSat = hue < 0 ? 0 : 64; - const int hueSafe = hue < 0 ? 0 : hue; - // Depth is what stops a light stage reading as a washed-out near-white - // copy of the page behind the banner: deepen the lower pastel band and - // raise saturation so the hue is clearly present while staying frosted. - auto pastel = [hueSafe, stageSat](int lightness) { return QColor::fromHsl(hueSafe, stageSat, lightness); }; - auto pastelLower = [hueSafe](int lightness) { return QColor::fromHsl(hueSafe, 76, lightness); }; - // Brightness-lifted accent for additive glows: the raw accent on a - // light stage must be mid-bright to read instead of washing out, so - // lift lightness and saturation together. - const int accentLightness = qBound(158, accentStrong.lightness() + 82, 198); - const int accentSaturation = hue < 0 ? 0 : qMax(accentStrong.hslSaturation(), 180); - const QColor liftedAccent = - hue < 0 ? accentStrong : QColor::fromHsl(hueSafe, accentSaturation, accentLightness); - // The centre glow (and logo tint in QML) uses the deep accent itself: - // a coloured halo/fill behind the logo instead of a white or black one. - return {pastel(214), pastelLower(186), liftedAccent, accentStrong, brandStrong, brandSoft, 0.80}; - } - - // Dark stage: force the window hue down to the banner's curated darkness, - // scaling saturation away so chromatic palettes tint it without going - // muddy. The accent is the bright, brand-driven tone (hue from the accent - // itself, never the -- often grey -- window), and it drives both the - // embers/fog and the logo glow so the mark tints like the light stage. - auto stage = [&window](int lightness) { - const int hue = window.hslHue(); - const int saturation = hue < 0 ? 0 : qBound(0, qRound(window.hslSaturation() * (lightness / 40.0)), 255); - return QColor::fromHsl(hue, saturation, lightness); - }; - const int accentHue = accentStrong.hslHue(); - const int accentHueSafe = accentHue < 0 ? 0 : accentHue; - const int accentLightness = qBound(150, accentStrong.lightness() + 70, 185); - const int accentSaturation = accentHue < 0 ? 0 : qMax(accentStrong.hslSaturation(), 160); - const QColor accent = - accentHue < 0 ? accentStrong : QColor::fromHsl(accentHueSafe, accentSaturation, accentLightness); - return {stage(29), stage(16), accent, accent, brandStrong, brandSoft, 0.62}; -} +// Near-black base palette -- the background is dark and quiet so the green +// accent stands out. +constexpr QRgb kColorA = 0x1A1A20; +constexpr QRgb kColorB = 0x0E0E12; +constexpr QRgb kAccent = 0x8BDD6B; } // namespace class GradientFallbackWidget : public QWidget @@ -113,27 +23,15 @@ class GradientFallbackWidget : public QWidget public: using QWidget::QWidget; - void setColors(const QColor &a, const QColor &b) - { - if (a != colorA || b != colorB) { - colorA = a; - colorB = b; - } - } - protected: void paintEvent(QPaintEvent *) override { QPainter painter(this); QLinearGradient gradient(0, 0, width(), height()); - gradient.setColorAt(0.0, colorA); - gradient.setColorAt(1.0, colorB); + gradient.setColorAt(0.0, QColor(kColorA)); + gradient.setColorAt(1.0, QColor(kColorB)); painter.fillRect(rect(), gradient); } - -private: - QColor colorA{QColor(kFallbackColorA)}; - QColor colorB{QColor(kFallbackColorB)}; }; BannerHost::BannerHost(QWidget *parent) : QWidget(parent) @@ -164,9 +62,6 @@ BannerHost::BannerHost(QWidget *parent) : QWidget(parent) connect(&clock, &QTimer::timeout, this, &BannerHost::tick); clock.setInterval(16); // ~60fps; the shader itself is cheap, this is just a wall clock - connect(themeManager, &ThemeManager::themeChanged, this, &BannerHost::applyThemeColors); - applyThemeColors(); - applyMotifPreset(currentMotif); updateAspect(); } @@ -228,9 +123,9 @@ void BannerHost::applyMotifPreset(Motif motif) const Preset p = presetFor(motif); - config->setColorA(bannerColorA); - config->setColorB(bannerColorB); - config->setAccent(bannerAccent); + config->setColorA(QColor(kColorA)); + config->setColorB(QColor(kColorB)); + config->setAccent(QColor(kAccent)); config->setLogoVisible(motif == Motif::Welcome); if (isFirstApply) { @@ -288,34 +183,8 @@ void BannerHost::hideEvent(QHideEvent *event) clock.stop(); } -void BannerHost::applyThemeColors() -{ - const SuggestedColors colors = suggestedBannerColors(); - bannerColorA = colors.colorA; - bannerColorB = colors.colorB; - bannerAccent = colors.accent; - - if (usingFallback) { - fallback->setColors(bannerColorA, bannerColorB); - fallback->update(); - } else if (config) { - config->setColorA(bannerColorA); - config->setColorB(bannerColorB); - config->setAccent(bannerAccent); - config->setGlowColor(colors.glowColor); - config->setBrandStrong(colors.brandStrong); - config->setBrandSoft(colors.brandSoft); - config->setVignetteMin(colors.vignetteMin); - } -} - void BannerHost::tick() { - // Palette previews (e.g. accent drags in the wizard's QuickSetupPanel) - // apply qApp->palette() without firing themeChanged, so re-derive here; - // BannerShaderConfig's setters are equality-guarded, so this is a no-op - // unless the colours actually changed. - applyThemeColors(); if (config) { qreal t = elapsed.elapsed() / 1000.0; config->setTime(t); diff --git a/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.h b/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.h index ac47b1141..2e230ad7f 100644 --- a/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.h +++ b/cockatrice/src/interface/widgets/onboarding/shader_banner_widget.h @@ -1,7 +1,6 @@ #ifndef SHADER_BANNER_WIDGET_H #define SHADER_BANNER_WIDGET_H -#include #include #include #include @@ -54,7 +53,6 @@ protected: private slots: void tick(); void onSceneGraphFailed(); - void applyThemeColors(); private: struct Preset @@ -75,12 +73,6 @@ private: BannerShaderConfig *config = nullptr; GradientFallbackWidget *fallback = nullptr; - // Palette-derived banner colours -- the theme's window hue forced down to - // the banner's curated darkness, plus the theme's Highlight as accent. - QColor bannerColorA; - QColor bannerColorB; - QColor bannerAccent; - QTimer clock; QElapsedTimer elapsed; Motif currentMotif = Motif::Welcome; diff --git a/cockatrice/src/interface/widgets/onboarding/shaders/brand_banner.frag b/cockatrice/src/interface/widgets/onboarding/shaders/brand_banner.frag index 2bf6d0abf..508bd4bc4 100644 --- a/cockatrice/src/interface/widgets/onboarding/shaders/brand_banner.frag +++ b/cockatrice/src/interface/widgets/onboarding/shaders/brand_banner.frag @@ -28,8 +28,6 @@ layout(std140, binding = 0) uniform buf vec4 uColorA; vec4 uColorB; vec4 uAccent; - vec4 uGlowColor; - float uVignetteMin; float uLogoGlow; }; @@ -121,7 +119,7 @@ vec3 backgroundField(vec2 uv, float time) // Accent-coloured fog layer: flowNoise peaks above 0.6 contribute accent float fog = flowNoise(uv * 0.8 + vec2(100.0, 50.0), time * 0.02); - col += uAccent.rgb * max(fog - 0.6, 0.0) * 0.14; + col += uAccent.rgb * max(fog - 0.6, 0.0) * 0.10; return col; } @@ -138,17 +136,14 @@ vec3 motifWelcome(vec2 uv, vec3 bg, float t) vec2 center = vec2(asp * 0.5, 0.5); float cDist = length(ac - center); - // Centre bloom at logo position; intensity scales with uLogoGlow. The - // QML brandGlow halo now supplies the primary logo surround (the two - // brand appColors), so this shader bloom is deliberately kept as a subtle - // ambience rather than a competing glow. + // Centre bloom at logo position; intensity scales with uLogoGlow float centreLight = bloom(cDist, 0.08 * asp, 0.40 * asp); - col += uGlowColor.rgb * centreLight * 0.20 * uLogoGlow; + col += centreLight * 0.20 * uLogoGlow; // Flow-noise shimmer gated by Gaussian mask at centre float shimmer = flowNoise(ac * 0.8 + vec2(55.0, 33.0), t * 0.05) * 0.5 + 0.5; float shimmerMask = exp(-(cDist * cDist) / (0.18 * asp * 0.18 * asp)); - col += uGlowColor.rgb * shimmer * shimmerMask * 0.04 * uLogoGlow; + col += shimmer * shimmerMask * 0.04 * uLogoGlow; // 48 ember particles: hash-seeded position, speed, size, brightness. // Embers within a distance threshold of centre are deflected into an @@ -167,8 +162,8 @@ vec3 motifWelcome(vec2 uv, vec3 bg, float t) float pX = baseX * asp + sin(t * driftFreq + fi * 1.7) * driftAmp * asp; float pY = fract(baseY + t * riseSpeed); - float size = 0.010 + hash21(vec2(fi * 2.9, uSeed * 4.7)) * 0.014; - float bright = 0.18 + hash21(vec2(fi * 6.1, uSeed * 0.9)) * 0.32; + float size = 0.006 + hash21(vec2(fi * 2.9, uSeed * 4.7)) * 0.012; + float bright = 0.15 + hash21(vec2(fi * 6.1, uSeed * 0.9)) * 0.30; // Fade out near top/bottom edges float edgeFade = smoothstep(0.0, 0.12, pY) * smoothstep(1.0, 0.88, pY); @@ -237,7 +232,7 @@ vec3 motifCardDatabase(vec2 uv, vec3 bg, float t) // Semi-transparent dark fill float fill = smoothstep(0.015, -0.005, d); - col = mix(col, uColorB.rgb * 0.60, fill * 0.62); + col = mix(col, uColorB.rgb * 0.55, fill * 0.50); // Accent outline float edge = smoothstep(0.035, 0.0, abs(d)); @@ -314,7 +309,7 @@ vec3 motifAccount(vec2 uv, vec3 bg, float t) // Node glow via bloom; intensity modulated by pulse float dist = length(ac - pos); - col += uAccent.rgb * bloom(dist, 0.018, 0.08) * mix(0.30, 0.55, pulse); + col += uAccent.rgb * bloom(dist, 0.018, 0.08) * mix(0.20, 0.45, pulse); } // Edges: connect nodes within a radius threshold @@ -328,19 +323,19 @@ vec3 motifAccount(vec2 uv, vec3 bg, float t) vec2 ba = nodePos[j] - nodePos[i]; float h = clamp(dot(pa, ba) / dot(ba, ba), 0.0, 1.0); float lineDist = length(pa - ba * h); - col += uAccent.rgb * smoothstep(0.010, 0.0, lineDist) * strength * 0.14; + col += uAccent.rgb * smoothstep(0.010, 0.0, lineDist) * strength * 0.10; } } } // Central bloom at banner centre float cDist = length(ac - center); - col += uAccent.rgb * bloom(cDist, 0.04, 0.25) * 0.20; + col += uAccent.rgb * bloom(cDist, 0.04, 0.25) * 0.12; // Periodic expanding ring from centre float ripplePhase = t * 0.4; float rippleDist = abs(cDist - fract(ripplePhase) * asp * 0.7); - col += uAccent.rgb * smoothstep(0.02, 0.0, rippleDist) * 0.14; + col += uAccent.rgb * smoothstep(0.02, 0.0, rippleDist) * 0.10; return col; } @@ -461,8 +456,6 @@ void main() else if (uMode < 4.5) col = motifPreferences(uv, bg, t); else col = motifFinish(uv, bg, t); - // Corner vignette; uVignetteMin is scheme-driven (0.62 on dark stages, - // gentler on light ones so near-white corners don't go muddy grey). - col *= mix(uVignetteMin, 1.0, vignette(uv)); + col *= mix(0.62, 1.0, vignette(uv)); fragColor = vec4(col, 1.0) * qt_Opacity; } diff --git a/cockatrice/src/interface/widgets/onboarding/shaders/brand_plate.frag b/cockatrice/src/interface/widgets/onboarding/shaders/brand_plate.frag deleted file mode 100644 index 43b798c9f..000000000 --- a/cockatrice/src/interface/widgets/onboarding/shaders/brand_plate.frag +++ /dev/null @@ -1,42 +0,0 @@ -#version 440 - -// The logo's gradient plate, drawn by us rather than the baked-in SVG: a -// linear blend between the two brand appColors (light AccentSoft at the -// top-left grading to dark AccentStrong at the bottom-right, mirroring -// cockatrice.svg's linearGradient4265-7-8 userSpaceOnUse axis), clipped to -// the bird's full silhouette via the full-color logo's alpha (uSilhouette). -// The white highlight path (cockatrice-logo-white) is overlaid in QML on top, -// exactly as the SVG stacks its white path over the gradient paths. Fully -// static: no glow, no breathing — the plate just sits there like the home -// widget's QPainter composite. - -layout(location = 0) in vec2 qt_TexCoord0; -layout(location = 0) out vec4 fragColor; - -layout(std140, binding = 0) uniform buf -{ - mat4 qt_Matrix; - float qt_Opacity; - vec4 uStrong; - vec4 uSoft; -}; - -// The full-color logo's alpha channel acts as the silhouette mask: the -// gradient only appears inside the bird, exactly like the SVG's gradient paths. -layout(binding = 1) uniform sampler2D uSilhouette; - -void main() -{ - // Recreate cockatrice.svg's own gradient geometry (linearGradient4265-7-8, - // userSpaceOnUse): light AccentSoft at the start point S=(-8.097,-97.746), - // dark AccentStrong at the end E=(162.455,295.208), on the SVG's 300x300 - // canvas. Normalized to UV space, V=E-S=(0.5685,1.3098), so - // t = dot(uv - S_norm, V)/|V|^2 with S_norm=(-0.0270,-0.3258). - float t = clamp(dot(qt_TexCoord0 - vec2(-0.02699, -0.32582), vec2(0.56851, 1.30985)) / 2.03891, 0.0, 1.0); - vec3 color = mix(uSoft.rgb, uStrong.rgb, t); - - // Anti-aliased silhouette clip from the full-color logo's alpha. - float alpha = texture(uSilhouette, qt_TexCoord0).a; - - fragColor = vec4(color * alpha, alpha) * qt_Opacity; -} \ No newline at end of file diff --git a/cockatrice/themes/Fusion/palette-default-dark.toml b/cockatrice/themes/Fusion/palette-default-dark.toml index b180e9b63..a988c2f14 100644 --- a/cockatrice/themes/Fusion/palette-default-dark.toml +++ b/cockatrice/themes/Fusion/palette-default-dark.toml @@ -11,15 +11,15 @@ ButtonText = #ffffffff Base = #ff2d2d2d Window = #ff1e1e1e Shadow = #ff000000 -Highlight = #ff139740 +Highlight = #ff148c3c HighlightedText = #ffffffff -Link = #ffc9fd62 -LinkVisited = #ff9ad43e +Link = #ff00f652 +LinkVisited = #ff00d346 AlternateBase = #ff353535 ToolTipBase = #ff3c3c3c ToolTipText = #ffd4d4d4 PlaceholderText = #80ffffff -Accent = #ffc9fd62 +Accent = #ff00d346 [Palette.Disabled] WindowText = #ff9d9d9d @@ -34,7 +34,7 @@ ButtonText = #ff9d9d9d Base = #ff1e1e1e Window = #ff1e1e1e Shadow = #ff000000 -Highlight = #ff139740 +Highlight = #ff148c3c HighlightedText = #ffffffff Link = #ff308cc6 LinkVisited = #ffff00ff @@ -59,8 +59,8 @@ Window = #ff1e1e1e Shadow = #ff000000 Highlight = #ff1e1e1e HighlightedText = #ffffffff -Link = #ffc9fd62 -LinkVisited = #ff9ad43e +Link = #ff00f652 +LinkVisited = #ff00d346 AlternateBase = #ff353535 ToolTipBase = #ff3c3c3c ToolTipText = #ffd4d4d4 @@ -69,5 +69,5 @@ Accent = #ff1e1e1e [AppColors] -AccentStrong = #ff139740 -AccentSoft = #ffc9fd62 +AccentStrong = #ff148c3c +AccentSoft = #ff78c850 diff --git a/cockatrice/themes/Fusion/palette-default-light.toml b/cockatrice/themes/Fusion/palette-default-light.toml index 5a1163a2b..b72b79b11 100644 --- a/cockatrice/themes/Fusion/palette-default-light.toml +++ b/cockatrice/themes/Fusion/palette-default-light.toml @@ -11,15 +11,15 @@ ButtonText = #ff000000 Base = #ffffffff Window = #fff0f0f0 Shadow = #ff696969 -Highlight = #ff139740 +Highlight = #ff148c3c HighlightedText = #ffffffff -Link = #ff0e6b31 -LinkVisited = #ff0a521f +Link = #ff0d5f28 +LinkVisited = #ff08401b AlternateBase = #ffe9e7e3 ToolTipBase = #ffffffdc ToolTipText = #ff000000 PlaceholderText = #80000000 -Accent = #ff139740 +Accent = #ff107532 [Palette.Disabled] WindowText = #ff787878 @@ -34,7 +34,7 @@ ButtonText = #ff787878 Base = #fff0f0f0 Window = #fff0f0f0 Shadow = #ff000000 -Highlight = #ff139740 +Highlight = #ff148c3c HighlightedText = #ffffffff Link = #ff0000ff LinkVisited = #ffff00ff @@ -59,8 +59,8 @@ Window = #fff0f0f0 Shadow = #ff696969 Highlight = #fff0f0f0 HighlightedText = #ff000000 -Link = #ff0e6b31 -LinkVisited = #ff0a521f +Link = #ff0d5f28 +LinkVisited = #ff08401b AlternateBase = #ffe9e7e3 ToolTipBase = #ffffffdc ToolTipText = #ff000000 @@ -69,5 +69,5 @@ Accent = #fff0f0f0 [AppColors] -AccentStrong = #ff139740 -AccentSoft = #ffc9fd62 +AccentStrong = #ff148c3c +AccentSoft = #ff78c850