mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-23 01:55:10 -07:00
WIP [UI] Theme-aware onboarding banner with frosted light mode
Banner colours now derive from palette tokens at ~60fps (tick-driven, equality-guarded setters) so scheme switches and live accent-picker previews apply instantly: - dark stages: byte-for-byte the original treatment (near-black stage from window hue, Highlight accent, white centre halo, vignette 0.62) - light stages: pastel accent-hue wash instead of a neutral grey copy, brightness-lifted accent for additive glow legibility, deep-Highlight halo (uGlowColor) instead of white blowout, gentler vignette (uVignetteMin 0.88) so corners don't go muddy - black logo silhouette variant selected on light stages - theme picker preseeded with brand green (brand_colors.h single source) WIP notes for next session: - real-pixel wizard screenshot check still pending (headless capture exists: Xvfb :77 + isolated XDG_DATA_HOME; shader vs fallback pixel analysis not finished) - user plans separately: promote Fusion to default theme, Default -> system
This commit is contained in:
parent
c1c20bcf92
commit
c2d4820f8b
10 changed files with 231 additions and 16 deletions
|
|
@ -403,6 +403,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/tabs/api/commander_spellbook/commander_bracket_widget.cpp
|
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/tabs/api/commander_spellbook/handle_commander_brackets.cpp
|
||||||
src/interface/widgets/onboarding/banner_shader_config.h
|
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.cpp
|
||||||
src/interface/widgets/onboarding/first_run_wizard.h
|
src/interface/widgets/onboarding/first_run_wizard.h
|
||||||
src/interface/widgets/onboarding/first_run_wizard_page.cpp
|
src/interface/widgets/onboarding/first_run_wizard_page.cpp
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
<qresource prefix="/">
|
<qresource prefix="/">
|
||||||
<file>resources/cardback.svg</file>
|
<file>resources/cardback.svg</file>
|
||||||
<file>resources/cockatrice.svg</file>
|
<file>resources/cockatrice.svg</file>
|
||||||
|
<file>resources/cockatrice-logo-black.svg</file>
|
||||||
<file>resources/cockatrice-logo-white.svg</file>
|
<file>resources/cockatrice-logo-white.svg</file>
|
||||||
<file>resources/hand.svg</file>
|
<file>resources/hand.svg</file>
|
||||||
<file>resources/hr.jpg</file>
|
<file>resources/hr.jpg</file>
|
||||||
|
|
|
||||||
21
cockatrice/resources/cockatrice-logo-black.svg
Normal file
21
cockatrice/resources/cockatrice-logo-black.svg
Normal file
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 6.8 KiB |
|
|
@ -38,8 +38,11 @@ class BannerShaderConfig : public QObject
|
||||||
Q_PROPERTY(QColor colorA READ colorA WRITE setColorA NOTIFY colorAChanged)
|
Q_PROPERTY(QColor colorA READ colorA WRITE setColorA NOTIFY colorAChanged)
|
||||||
Q_PROPERTY(QColor colorB READ colorB WRITE setColorB NOTIFY colorBChanged)
|
Q_PROPERTY(QColor colorB READ colorB WRITE setColorB NOTIFY colorBChanged)
|
||||||
Q_PROPERTY(QColor accent READ accent WRITE setAccent NOTIFY accentChanged)
|
Q_PROPERTY(QColor accent READ accent WRITE setAccent NOTIFY accentChanged)
|
||||||
|
Q_PROPERTY(QColor glowColor READ glowColor WRITE setGlowColor NOTIFY glowColorChanged)
|
||||||
|
Q_PROPERTY(qreal vignetteMin READ vignetteMin WRITE setVignetteMin NOTIFY vignetteMinChanged)
|
||||||
|
|
||||||
Q_PROPERTY(bool logoVisible READ logoVisible WRITE setLogoVisible NOTIFY logoVisibleChanged)
|
Q_PROPERTY(bool logoVisible READ logoVisible WRITE setLogoVisible NOTIFY logoVisibleChanged)
|
||||||
|
Q_PROPERTY(bool logoDark READ logoDark WRITE setLogoDark NOTIFY logoDarkChanged)
|
||||||
Q_PROPERTY(qreal logoGlow READ logoGlow WRITE setLogoGlow NOTIFY logoGlowChanged)
|
Q_PROPERTY(qreal logoGlow READ logoGlow WRITE setLogoGlow NOTIFY logoGlowChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -185,6 +188,30 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QColor glowColor() const
|
||||||
|
{
|
||||||
|
return m_glowColor;
|
||||||
|
}
|
||||||
|
void setGlowColor(const QColor &c)
|
||||||
|
{
|
||||||
|
if (c != m_glowColor) {
|
||||||
|
m_glowColor = c;
|
||||||
|
emit glowColorChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal vignetteMin() const
|
||||||
|
{
|
||||||
|
return m_vignetteMin;
|
||||||
|
}
|
||||||
|
void setVignetteMin(qreal v)
|
||||||
|
{
|
||||||
|
if (v != m_vignetteMin) {
|
||||||
|
m_vignetteMin = v;
|
||||||
|
emit vignetteMinChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool logoVisible() const
|
bool logoVisible() const
|
||||||
{
|
{
|
||||||
return m_logoVisible;
|
return m_logoVisible;
|
||||||
|
|
@ -197,6 +224,18 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool logoDark() const
|
||||||
|
{
|
||||||
|
return m_logoDark;
|
||||||
|
}
|
||||||
|
void setLogoDark(bool v)
|
||||||
|
{
|
||||||
|
if (v != m_logoDark) {
|
||||||
|
m_logoDark = v;
|
||||||
|
emit logoDarkChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
qreal logoGlow() const
|
qreal logoGlow() const
|
||||||
{
|
{
|
||||||
return m_logoGlow;
|
return m_logoGlow;
|
||||||
|
|
@ -222,7 +261,10 @@ signals:
|
||||||
void colorAChanged();
|
void colorAChanged();
|
||||||
void colorBChanged();
|
void colorBChanged();
|
||||||
void accentChanged();
|
void accentChanged();
|
||||||
|
void glowColorChanged();
|
||||||
|
void vignetteMinChanged();
|
||||||
void logoVisibleChanged();
|
void logoVisibleChanged();
|
||||||
|
void logoDarkChanged();
|
||||||
void logoGlowChanged();
|
void logoGlowChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -239,11 +281,17 @@ private:
|
||||||
|
|
||||||
bool m_frontIsA = true;
|
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_colorA{0x1A, 0x1A, 0x20};
|
||||||
QColor m_colorB{0x0E, 0x0E, 0x12};
|
QColor m_colorB{0x0E, 0x0E, 0x12};
|
||||||
QColor m_accent{0x8B, 0xDD, 0x6B};
|
QColor m_accent{0x8B, 0xDD, 0x6B};
|
||||||
|
QColor m_glowColor{Qt::white};
|
||||||
|
qreal m_vignetteMin = 0.62;
|
||||||
|
|
||||||
bool m_logoVisible = false;
|
bool m_logoVisible = false;
|
||||||
|
bool m_logoDark = false;
|
||||||
qreal m_logoGlow = 1.0;
|
qreal m_logoGlow = 1.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
15
cockatrice/src/interface/widgets/onboarding/brand_colors.h
Normal file
15
cockatrice/src/interface/widgets/onboarding/brand_colors.h
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef BRAND_COLORS_H
|
||||||
|
#define BRAND_COLORS_H
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
|
||||||
|
/** @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
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
#include "../../interface/palette_editor/quick_setup_panel.h"
|
#include "../../interface/palette_editor/quick_setup_panel.h"
|
||||||
#include "../../interface/theme_manager.h"
|
#include "../../interface/theme_manager.h"
|
||||||
#include "../../interface/widgets/general/background_sources.h"
|
#include "../../interface/widgets/general/background_sources.h"
|
||||||
|
#include "../brand_colors.h"
|
||||||
#include "libcockatrice/settings/appearance_settings.h"
|
#include "libcockatrice/settings/appearance_settings.h"
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
|
@ -30,6 +31,12 @@ ThemeSetupPage::ThemeSetupPage(QWidget *parent) : FirstRunWizardPage(parent)
|
||||||
|
|
||||||
quickSetupPanel = new QuickSetupPanel(this);
|
quickSetupPanel = new QuickSetupPanel(this);
|
||||||
|
|
||||||
|
// Preseed with the brand green so a fresh install's generated palette --
|
||||||
|
// and therefore the banner accent, which follows QPalette::Highlight --
|
||||||
|
// keeps the Cockatrice identity until the user picks their own look.
|
||||||
|
// setAccentColor blocks signals, so this never triggers a generation.
|
||||||
|
quickSetupPanel->setAccentColor(kCockatriceBrandGreen);
|
||||||
|
|
||||||
connect(themeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ThemeSetupPage::onThemeChanged);
|
connect(themeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ThemeSetupPage::onThemeChanged);
|
||||||
connect(schemeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ThemeSetupPage::onSchemeChanged);
|
connect(schemeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &ThemeSetupPage::onSchemeChanged);
|
||||||
connect(quickSetupPanel, &QuickSetupPanel::valueChanged, this, &ThemeSetupPage::onGenerateFromAccent);
|
connect(quickSetupPanel, &QuickSetupPanel::valueChanged, this, &ThemeSetupPage::onGenerateFromAccent);
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ Item {
|
||||||
property vector4d uColorA: Qt.vector4d(bannerConfig.colorA.r, bannerConfig.colorA.g, bannerConfig.colorA.b, 1.0)
|
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 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 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
|
property real uLogoGlow: bannerConfig.logoGlow
|
||||||
fragmentShader: "qrc:/onboarding/shaders/brand_banner.frag.qsb"
|
fragmentShader: "qrc:/onboarding/shaders/brand_banner.frag.qsb"
|
||||||
}
|
}
|
||||||
|
|
@ -33,16 +35,21 @@ Item {
|
||||||
property vector4d uColorA: Qt.vector4d(bannerConfig.colorA.r, bannerConfig.colorA.g, bannerConfig.colorA.b, 1.0)
|
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 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 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
|
property real uLogoGlow: bannerConfig.logoGlow
|
||||||
fragmentShader: "qrc:/onboarding/shaders/brand_banner.frag.qsb"
|
fragmentShader: "qrc:/onboarding/shaders/brand_banner.frag.qsb"
|
||||||
}
|
}
|
||||||
|
|
||||||
// The hero logo itself — breathes cleanly over a 0.5–1.0 opacity range
|
// The hero logo itself — breathes cleanly over a 0.5–1.0 opacity range.
|
||||||
|
// White silhouette on dark stages, black on light ones, so it stays
|
||||||
|
// readable in both modes.
|
||||||
Image {
|
Image {
|
||||||
id: logo
|
id: logo
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
visible: bannerConfig.logoVisible
|
visible: bannerConfig.logoVisible
|
||||||
source: "qrc:/resources/cockatrice-logo-white.svg"
|
source: bannerConfig.logoDark ? "qrc:/resources/cockatrice-logo-black.svg"
|
||||||
|
: "qrc:/resources/cockatrice-logo-white.svg"
|
||||||
width: root.height * 0.6
|
width: root.height * 0.6
|
||||||
height: width * (sourceSize.height > 0 ? sourceSize.height / Math.max(sourceSize.width, 1) : 1)
|
height: width * (sourceSize.height > 0 ? sourceSize.height / Math.max(sourceSize.width, 1) : 1)
|
||||||
fillMode: Image.PreserveAspectFit
|
fillMode: Image.PreserveAspectFit
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
#include "shader_banner_widget.h"
|
#include "shader_banner_widget.h"
|
||||||
|
|
||||||
|
#include "../../theme_manager.h"
|
||||||
#include "banner_shader_config.h"
|
#include "banner_shader_config.h"
|
||||||
|
#include "brand_colors.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QQmlContext>
|
#include <QQmlContext>
|
||||||
#include <QQmlEngine>
|
#include <QQmlEngine>
|
||||||
|
|
@ -11,11 +14,68 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
// Near-black base palette -- the background is dark and quiet so the green
|
// Curated near-black stage -- used only when the active palette resolves no
|
||||||
// accent stands out.
|
// usable window colour. Matches the banner's original design (dark and quiet
|
||||||
constexpr QRgb kColorA = 0x1A1A20;
|
// so the accent stands out) and satisfies design-plans §2.1's "identity
|
||||||
constexpr QRgb kColorB = 0x0E0E12;
|
// survives a bare palette".
|
||||||
constexpr QRgb kAccent = 0x8BDD6B;
|
constexpr QRgb kFallbackColorA = 0x1A1A20;
|
||||||
|
constexpr QRgb kFallbackColorB = 0x0E0E12;
|
||||||
|
|
||||||
|
struct SuggestedColors
|
||||||
|
{
|
||||||
|
QColor colorA;
|
||||||
|
QColor colorB;
|
||||||
|
QColor accent;
|
||||||
|
QColor glowColor;
|
||||||
|
qreal vignetteMin = 0.62;
|
||||||
|
bool lightStage = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
SuggestedColors suggestedBannerColors()
|
||||||
|
{
|
||||||
|
const QPalette &pal = qApp->palette();
|
||||||
|
const QColor window = pal.color(QPalette::Active, QPalette::Window);
|
||||||
|
const QColor highlight = pal.color(QPalette::Active, QPalette::Highlight);
|
||||||
|
if (!window.isValid() || !highlight.isValid()) {
|
||||||
|
return {
|
||||||
|
QColor(kFallbackColorA), QColor(kFallbackColorB), kCockatriceBrandGreen, QColor(Qt::white), 0.62, false};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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 Highlight hue instead of a plain near-white copy: a gentle mint
|
||||||
|
// 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 = highlight.hslHue();
|
||||||
|
// Achromatic accents (grey) get a neutral near-white stage instead.
|
||||||
|
const int stageSat = hue < 0 ? 0 : 35;
|
||||||
|
const int hueSafe = hue < 0 ? 0 : hue;
|
||||||
|
auto pastel = [hueSafe, stageSat](int lightness) { return QColor::fromHsl(hueSafe, stageSat, lightness); };
|
||||||
|
// Brightness-lifted accent for additive glows: Highlight on a light
|
||||||
|
// stage must be mid-bright to read (the shipped light Highlight is a
|
||||||
|
// deep green that washes out additively against white).
|
||||||
|
const int accentLightness = qBound(120, highlight.lightness() + 70, 165);
|
||||||
|
const int accentSaturation = hue < 0 ? 0 : qMax(highlight.hslSaturation(), 140);
|
||||||
|
const QColor liftedAccent = hue < 0 ? highlight : QColor::fromHsl(hueSafe, accentSaturation, accentLightness);
|
||||||
|
// The centre glow uses the deep Highlight itself -- a coloured halo
|
||||||
|
// behind the dark logo instead of a white blowout.
|
||||||
|
return {pastel(247), pastel(231), liftedAccent, highlight, 0.88, true};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dark stage: force the window hue down to the banner's curated darkness,
|
||||||
|
// scaling saturation away so chromatic palettes tint it without going
|
||||||
|
// muddy. White glow and the original strong vignette stay untouched.
|
||||||
|
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);
|
||||||
|
};
|
||||||
|
return {stage(29), stage(16), QColor(highlight), QColor(Qt::white), 0.62, false};
|
||||||
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
class GradientFallbackWidget : public QWidget
|
class GradientFallbackWidget : public QWidget
|
||||||
|
|
@ -23,15 +83,27 @@ class GradientFallbackWidget : public QWidget
|
||||||
public:
|
public:
|
||||||
using QWidget::QWidget;
|
using QWidget::QWidget;
|
||||||
|
|
||||||
|
void setColors(const QColor &a, const QColor &b)
|
||||||
|
{
|
||||||
|
if (a != colorA || b != colorB) {
|
||||||
|
colorA = a;
|
||||||
|
colorB = b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void paintEvent(QPaintEvent *) override
|
void paintEvent(QPaintEvent *) override
|
||||||
{
|
{
|
||||||
QPainter painter(this);
|
QPainter painter(this);
|
||||||
QLinearGradient gradient(0, 0, width(), height());
|
QLinearGradient gradient(0, 0, width(), height());
|
||||||
gradient.setColorAt(0.0, QColor(kColorA));
|
gradient.setColorAt(0.0, colorA);
|
||||||
gradient.setColorAt(1.0, QColor(kColorB));
|
gradient.setColorAt(1.0, colorB);
|
||||||
painter.fillRect(rect(), gradient);
|
painter.fillRect(rect(), gradient);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QColor colorA{QColor(kFallbackColorA)};
|
||||||
|
QColor colorB{QColor(kFallbackColorB)};
|
||||||
};
|
};
|
||||||
|
|
||||||
BannerHost::BannerHost(QWidget *parent) : QWidget(parent)
|
BannerHost::BannerHost(QWidget *parent) : QWidget(parent)
|
||||||
|
|
@ -62,6 +134,9 @@ BannerHost::BannerHost(QWidget *parent) : QWidget(parent)
|
||||||
connect(&clock, &QTimer::timeout, this, &BannerHost::tick);
|
connect(&clock, &QTimer::timeout, this, &BannerHost::tick);
|
||||||
clock.setInterval(16); // ~60fps; the shader itself is cheap, this is just a wall clock
|
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);
|
applyMotifPreset(currentMotif);
|
||||||
updateAspect();
|
updateAspect();
|
||||||
}
|
}
|
||||||
|
|
@ -123,9 +198,9 @@ void BannerHost::applyMotifPreset(Motif motif)
|
||||||
|
|
||||||
const Preset p = presetFor(motif);
|
const Preset p = presetFor(motif);
|
||||||
|
|
||||||
config->setColorA(QColor(kColorA));
|
config->setColorA(bannerColorA);
|
||||||
config->setColorB(QColor(kColorB));
|
config->setColorB(bannerColorB);
|
||||||
config->setAccent(QColor(kAccent));
|
config->setAccent(bannerAccent);
|
||||||
config->setLogoVisible(motif == Motif::Welcome);
|
config->setLogoVisible(motif == Motif::Welcome);
|
||||||
|
|
||||||
if (isFirstApply) {
|
if (isFirstApply) {
|
||||||
|
|
@ -183,8 +258,33 @@ void BannerHost::hideEvent(QHideEvent *event)
|
||||||
clock.stop();
|
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->setVignetteMin(colors.vignetteMin);
|
||||||
|
config->setLogoDark(colors.lightStage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BannerHost::tick()
|
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) {
|
if (config) {
|
||||||
qreal t = elapsed.elapsed() / 1000.0;
|
qreal t = elapsed.elapsed() / 1000.0;
|
||||||
config->setTime(t);
|
config->setTime(t);
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef SHADER_BANNER_WIDGET_H
|
#ifndef SHADER_BANNER_WIDGET_H
|
||||||
#define SHADER_BANNER_WIDGET_H
|
#define SHADER_BANNER_WIDGET_H
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
#include <QElapsedTimer>
|
#include <QElapsedTimer>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
@ -53,6 +54,7 @@ protected:
|
||||||
private slots:
|
private slots:
|
||||||
void tick();
|
void tick();
|
||||||
void onSceneGraphFailed();
|
void onSceneGraphFailed();
|
||||||
|
void applyThemeColors();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Preset
|
struct Preset
|
||||||
|
|
@ -73,6 +75,12 @@ private:
|
||||||
BannerShaderConfig *config = nullptr;
|
BannerShaderConfig *config = nullptr;
|
||||||
GradientFallbackWidget *fallback = 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;
|
QTimer clock;
|
||||||
QElapsedTimer elapsed;
|
QElapsedTimer elapsed;
|
||||||
Motif currentMotif = Motif::Welcome;
|
Motif currentMotif = Motif::Welcome;
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,8 @@ layout(std140, binding = 0) uniform buf
|
||||||
vec4 uColorA;
|
vec4 uColorA;
|
||||||
vec4 uColorB;
|
vec4 uColorB;
|
||||||
vec4 uAccent;
|
vec4 uAccent;
|
||||||
|
vec4 uGlowColor;
|
||||||
|
float uVignetteMin;
|
||||||
float uLogoGlow;
|
float uLogoGlow;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -136,14 +138,17 @@ vec3 motifWelcome(vec2 uv, vec3 bg, float t)
|
||||||
vec2 center = vec2(asp * 0.5, 0.5);
|
vec2 center = vec2(asp * 0.5, 0.5);
|
||||||
float cDist = length(ac - center);
|
float cDist = length(ac - center);
|
||||||
|
|
||||||
// Centre bloom at logo position; intensity scales with uLogoGlow
|
// Centre bloom at logo position; intensity scales with uLogoGlow. It
|
||||||
|
// uses the scheme-driven uGlowColor rather than plain white so light
|
||||||
|
// stages don't blow out (white halo on a near-white field) -- BannerHost
|
||||||
|
// feeds white on dark stages and the deep accent tone on light ones.
|
||||||
float centreLight = bloom(cDist, 0.08 * asp, 0.40 * asp);
|
float centreLight = bloom(cDist, 0.08 * asp, 0.40 * asp);
|
||||||
col += centreLight * 0.20 * uLogoGlow;
|
col += uGlowColor.rgb * centreLight * 0.20 * uLogoGlow;
|
||||||
|
|
||||||
// Flow-noise shimmer gated by Gaussian mask at centre
|
// 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 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));
|
float shimmerMask = exp(-(cDist * cDist) / (0.18 * asp * 0.18 * asp));
|
||||||
col += shimmer * shimmerMask * 0.04 * uLogoGlow;
|
col += uGlowColor.rgb * shimmer * shimmerMask * 0.04 * uLogoGlow;
|
||||||
|
|
||||||
// 48 ember particles: hash-seeded position, speed, size, brightness.
|
// 48 ember particles: hash-seeded position, speed, size, brightness.
|
||||||
// Embers within a distance threshold of centre are deflected into an
|
// Embers within a distance threshold of centre are deflected into an
|
||||||
|
|
@ -456,6 +461,8 @@ void main()
|
||||||
else if (uMode < 4.5) col = motifPreferences(uv, bg, t);
|
else if (uMode < 4.5) col = motifPreferences(uv, bg, t);
|
||||||
else col = motifFinish(uv, bg, t);
|
else col = motifFinish(uv, bg, t);
|
||||||
|
|
||||||
col *= mix(0.62, 1.0, vignette(uv));
|
// 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));
|
||||||
fragColor = vec4(col, 1.0) * qt_Opacity;
|
fragColor = vec4(col, 1.0) * qt_Opacity;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue