mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-27 00:14:40 -07:00
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
* [App] Add onboarding wizard Took 10 minutes Took 3 minutes Took 7 minutes Took 9 minutes Took 2 minutes Took 1 minute Took 7 minutes * Adjust CI Took 14 minutes Took 56 seconds Took 2 seconds Took 3 seconds * Adjust CI again Took 14 minutes Took 2 seconds * Comments and fixes Took 9 seconds Took 1 minute * Rebase. Took 5 minutes Took 50 seconds Took 15 seconds * Comments. Took 7 minutes * CI lol Took 3 minutes * CI again lol Took 4 minutes * Drop some settings, add some new ones. Took 19 minutes * Resize when expanding section Took 4 minutes Took 3 minutes Took 7 minutes --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
195 lines
5 KiB
C++
195 lines
5 KiB
C++
#include "shader_banner_widget.h"
|
|
|
|
#include "banner_shader_config.h"
|
|
|
|
#include <QPainter>
|
|
#include <QQmlContext>
|
|
#include <QQmlEngine>
|
|
#include <QQuickWidget>
|
|
#include <QResizeEvent>
|
|
#include <QStackedLayout>
|
|
|
|
namespace
|
|
{
|
|
// 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
|
|
{
|
|
public:
|
|
using QWidget::QWidget;
|
|
|
|
protected:
|
|
void paintEvent(QPaintEvent *) override
|
|
{
|
|
QPainter painter(this);
|
|
QLinearGradient gradient(0, 0, width(), height());
|
|
gradient.setColorAt(0.0, QColor(kColorA));
|
|
gradient.setColorAt(1.0, QColor(kColorB));
|
|
painter.fillRect(rect(), gradient);
|
|
}
|
|
};
|
|
|
|
BannerHost::BannerHost(QWidget *parent) : QWidget(parent)
|
|
{
|
|
setFixedHeight(150);
|
|
|
|
stack = new QStackedLayout(this);
|
|
stack->setContentsMargins(0, 0, 0, 0);
|
|
|
|
fallback = new GradientFallbackWidget(this);
|
|
stack->addWidget(fallback);
|
|
|
|
quickWidget = new QQuickWidget(this);
|
|
quickWidget->setResizeMode(QQuickWidget::SizeRootObjectToView);
|
|
|
|
config = new BannerShaderConfig(quickWidget->engine());
|
|
quickWidget->rootContext()->setContextProperty("bannerConfig", config);
|
|
quickWidget->setSource(QUrl("qrc:/onboarding/qml/BrandBanner.qml"));
|
|
|
|
if (quickWidget->status() == QQuickWidget::Error) {
|
|
activateFallback();
|
|
} else {
|
|
connect(quickWidget, &QQuickWidget::sceneGraphError, this, &BannerHost::onSceneGraphFailed);
|
|
stack->addWidget(quickWidget);
|
|
stack->setCurrentWidget(quickWidget);
|
|
}
|
|
|
|
connect(&clock, &QTimer::timeout, this, &BannerHost::tick);
|
|
clock.setInterval(16); // ~60fps; the shader itself is cheap, this is just a wall clock
|
|
|
|
applyMotifPreset(currentMotif);
|
|
updateAspect();
|
|
}
|
|
|
|
void BannerHost::activateFallback()
|
|
{
|
|
if (usingFallback) {
|
|
return;
|
|
}
|
|
usingFallback = true;
|
|
clock.stop();
|
|
stack->setCurrentWidget(fallback);
|
|
|
|
if (quickWidget) {
|
|
quickWidget->deleteLater(); // takes BannerShaderConfig (parented to its engine) with it
|
|
quickWidget = nullptr;
|
|
config = nullptr;
|
|
}
|
|
}
|
|
|
|
void BannerHost::onSceneGraphFailed()
|
|
{
|
|
activateFallback();
|
|
}
|
|
|
|
void BannerHost::setMotif(Motif motif)
|
|
{
|
|
currentMotif = motif;
|
|
applyMotifPreset(motif);
|
|
}
|
|
|
|
BannerHost::Preset BannerHost::presetFor(Motif motif)
|
|
{
|
|
// speed/seed tuned per motif so e.g. the network "pulse" (Account) reads
|
|
// at a deliberately calmer cadence than the data "scan" lines
|
|
// (Preferences), even though both come from the same shader.
|
|
switch (motif) {
|
|
case Motif::Welcome:
|
|
return {0.0, 0.6, 0.15};
|
|
case Motif::CardDatabase:
|
|
return {1.0, 1.3, 0.42};
|
|
case Motif::Theming:
|
|
return {2.0, 1.2, 0.73};
|
|
case Motif::Account:
|
|
return {3.0, 0.8, 0.28};
|
|
case Motif::Preferences:
|
|
return {4.0, 1.0, 0.61};
|
|
case Motif::Finish:
|
|
return {5.0, 1.0, 0.91};
|
|
}
|
|
return {0.0, 0.6, 0.15};
|
|
}
|
|
|
|
void BannerHost::applyMotifPreset(Motif motif)
|
|
{
|
|
if (usingFallback || !config) {
|
|
return;
|
|
}
|
|
|
|
const Preset p = presetFor(motif);
|
|
|
|
config->setColorA(QColor(kColorA));
|
|
config->setColorB(QColor(kColorB));
|
|
config->setAccent(QColor(kAccent));
|
|
config->setLogoVisible(motif == Motif::Welcome);
|
|
|
|
if (isFirstApply) {
|
|
// Nothing on screen yet -- write straight into the front bank, no
|
|
// crossfade needed for the very first paint.
|
|
config->setModeA(p.mode);
|
|
config->setSpeedA(p.speed);
|
|
config->setSeedA(p.seed);
|
|
config->setFrontIsA(true);
|
|
isFirstApply = false;
|
|
return;
|
|
}
|
|
|
|
// Write the new preset into whichever bank is currently hidden, then
|
|
// flip which one is front. QML's opacity Behavior does the actual
|
|
// crossfade -- BannerHost never animates anything itself.
|
|
if (config->frontIsA()) {
|
|
config->setModeB(p.mode);
|
|
config->setSpeedB(p.speed);
|
|
config->setSeedB(p.seed);
|
|
config->setFrontIsA(false);
|
|
} else {
|
|
config->setModeA(p.mode);
|
|
config->setSpeedA(p.speed);
|
|
config->setSeedA(p.seed);
|
|
config->setFrontIsA(true);
|
|
}
|
|
}
|
|
|
|
void BannerHost::updateAspect()
|
|
{
|
|
if (config && height() > 0) {
|
|
config->setAspect(qreal(width()) / qreal(height()));
|
|
}
|
|
}
|
|
|
|
void BannerHost::resizeEvent(QResizeEvent *event)
|
|
{
|
|
QWidget::resizeEvent(event);
|
|
updateAspect();
|
|
}
|
|
|
|
void BannerHost::showEvent(QShowEvent *event)
|
|
{
|
|
QWidget::showEvent(event);
|
|
if (!usingFallback) {
|
|
elapsed.restart();
|
|
clock.start();
|
|
}
|
|
}
|
|
|
|
void BannerHost::hideEvent(QHideEvent *event)
|
|
{
|
|
QWidget::hideEvent(event);
|
|
clock.stop();
|
|
}
|
|
|
|
void BannerHost::tick()
|
|
{
|
|
if (config) {
|
|
qreal t = elapsed.elapsed() / 1000.0;
|
|
config->setTime(t);
|
|
// Visible breathing for the logo: oscillates between 0.0 and 1.0
|
|
qreal glow = 0.5 + 0.5 * qSin(t * 0.4);
|
|
config->setLogoGlow(glow);
|
|
}
|
|
}
|