mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-28 08:52:19 -07:00
Animate life changes with a counter flash and battlefield shimmer
- Life loss pulses the player's life counter in the theme accent color - The battlefield table zone shimmers crimson on damage - Respects the global + per-effect animation toggles
This commit is contained in:
parent
c7ad813619
commit
33f8616328
11 changed files with 238 additions and 8 deletions
|
|
@ -29,8 +29,9 @@ AbstractCounter::AbstractCounter(CounterState *state,
|
||||||
{
|
{
|
||||||
setAcceptHoverEvents(true);
|
setAcceptHoverEvents(true);
|
||||||
|
|
||||||
connect(state, &CounterState::valueChanged, this, [this](int, int newValue) {
|
connect(state, &CounterState::valueChanged, this, [this](int oldValue, int newValue) {
|
||||||
value = newValue;
|
value = newValue;
|
||||||
|
onValueChanged(oldValue, newValue);
|
||||||
update();
|
update();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -228,3 +229,9 @@ void AbstractCounterDialog::changeValue(int diff)
|
||||||
curValue += diff;
|
curValue += diff;
|
||||||
setTextValue(QString::number(curValue));
|
setTextValue(QString::number(curValue));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AbstractCounter::onValueChanged(int /*oldValue*/, int /*newValue*/)
|
||||||
|
{
|
||||||
|
// Default: no feedback. Subclasses such as PlayerCounter override this to
|
||||||
|
// flash the counter on meaningful changes (life gain/loss).
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,9 @@ protected:
|
||||||
bool hovered = false;
|
bool hovered = false;
|
||||||
bool useNameForShortcut;
|
bool useNameForShortcut;
|
||||||
|
|
||||||
|
// Hook for subclasses that need per-value-change feedback (e.g. life-total flash).
|
||||||
|
virtual void onValueChanged(int oldValue, int newValue);
|
||||||
|
|
||||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
|
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
|
||||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
|
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
|
||||||
|
|
|
||||||
|
|
@ -188,6 +188,12 @@ void PlayerGraphicsItem::onCounterAdded(CounterState *state)
|
||||||
AbstractCounter *widget;
|
AbstractCounter *widget;
|
||||||
if (state->getName() == "life") {
|
if (state->getName() == "life") {
|
||||||
widget = playerTarget->addCounter(state);
|
widget = playerTarget->addCounter(state);
|
||||||
|
// design-game: taking damage shimmers the player's table zone crimson.
|
||||||
|
connect(state, &CounterState::valueChanged, this, [this](int oldValue, int newValue) {
|
||||||
|
if (newValue < oldValue) {
|
||||||
|
tableZoneGraphicsItem->triggerDamageShimmer();
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
widget = new GeneralCounter(state, player, true, this);
|
widget = new GeneralCounter(state, player, true, this);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
#include "player_target.h"
|
#include "player_target.h"
|
||||||
|
|
||||||
|
#include "../../client/settings/cache_settings.h"
|
||||||
#include "../../game/player/player_logic.h"
|
#include "../../game/player/player_logic.h"
|
||||||
#include "../../interface/pixel_map_generator.h"
|
#include "../../interface/pixel_map_generator.h"
|
||||||
|
#include "../../interface/theme_manager.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPixmapCache>
|
#include <QPixmapCache>
|
||||||
|
#include <QTimer>
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
|
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
|
||||||
|
|
||||||
|
|
@ -21,8 +25,10 @@ QRectF PlayerCounter::boundingRect() const
|
||||||
|
|
||||||
void PlayerCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
void PlayerCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||||
{
|
{
|
||||||
const int radius = 8;
|
// design-game: life totals live in a fully-rounded translucent HUD pill
|
||||||
const qreal border = 1;
|
// with an accent (Mana Green) border and mono numerals.
|
||||||
|
const int radius = 15;
|
||||||
|
const qreal border = 1.5;
|
||||||
QPainterPath path(QPointF(50 - border / 2, border / 2));
|
QPainterPath path(QPointF(50 - border / 2, border / 2));
|
||||||
path.lineTo(radius, border / 2);
|
path.lineTo(radius, border / 2);
|
||||||
path.arcTo(border / 2, border / 2, 2 * radius, 2 * radius, 90, 90);
|
path.arcTo(border / 2, border / 2, 2 * radius, 2 * radius, 90, 90);
|
||||||
|
|
@ -30,21 +36,64 @@ void PlayerCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*
|
||||||
path.lineTo(50 - border / 2, 30 - border / 2);
|
path.lineTo(50 - border / 2, 30 - border / 2);
|
||||||
path.closeSubpath();
|
path.closeSubpath();
|
||||||
|
|
||||||
QPen pen(QColor(100, 100, 100));
|
QPen pen(qApp->palette().highlight().color());
|
||||||
pen.setWidth(border);
|
pen.setWidthF(border);
|
||||||
painter->setPen(pen);
|
painter->setPen(pen);
|
||||||
painter->setBrush(hovered ? QColor(50, 50, 50, 160) : QColor(0, 0, 0, 160));
|
painter->setBrush(hovered ? QColor(18, 24, 38, 200) : QColor(11, 14, 20, 184));
|
||||||
|
|
||||||
painter->drawPath(path);
|
painter->drawPath(path);
|
||||||
|
|
||||||
QRectF translatedRect = path.controlPointRect();
|
QRectF translatedRect = path.controlPointRect();
|
||||||
QSize translatedSize = translatedRect.size().toSize();
|
QSize translatedSize = translatedRect.size().toSize();
|
||||||
QFont font("Serif");
|
QFont font = themeManager->monoFont();
|
||||||
font.setWeight(QFont::Bold);
|
font.setWeight(QFont::Bold);
|
||||||
font.setPixelSize(qMax(qRound(translatedSize.height() / 1.3), 9));
|
font.setPixelSize(qMax(qRound(translatedSize.height() / 1.3), 9));
|
||||||
painter->setFont(font);
|
painter->setFont(font);
|
||||||
painter->setPen(Qt::white);
|
painter->setPen(Qt::white);
|
||||||
painter->drawText(translatedRect, Qt::AlignCenter, QString::number(value));
|
painter->drawText(translatedRect, Qt::AlignCenter, QString::number(value));
|
||||||
|
|
||||||
|
// Life-change flash: emerald on gain, red on loss, decaying over a few ticks.
|
||||||
|
if (flashAlpha > 0) {
|
||||||
|
painter->save();
|
||||||
|
QColor flashColor = flashDelta > 0 ? QColor(52, 224, 122) : QColor(239, 68, 68);
|
||||||
|
flashColor.setAlphaF(0.45 * flashAlpha);
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
painter->setBrush(flashColor);
|
||||||
|
painter->setOpacity(0.85);
|
||||||
|
painter->drawPath(path);
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerCounter::onValueChanged(int oldValue, int newValue)
|
||||||
|
{
|
||||||
|
flashDelta = newValue - oldValue;
|
||||||
|
if (flashDelta == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SettingsCache::instance().userInterface().getAnimationsEnabled() ||
|
||||||
|
!SettingsCache::instance().userInterface().getLifeCounterAnimationsEnabled()) {
|
||||||
|
flashAlpha = 0.0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
flashAlpha = 1.0;
|
||||||
|
if (flashTimer == nullptr) {
|
||||||
|
flashTimer = new QTimer(this);
|
||||||
|
connect(flashTimer, &QTimer::timeout, this, &PlayerCounter::flashTick);
|
||||||
|
}
|
||||||
|
flashTimer->start(50);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlayerCounter::flashTick()
|
||||||
|
{
|
||||||
|
flashAlpha -= 0.12;
|
||||||
|
if (flashAlpha <= 0.0) {
|
||||||
|
flashAlpha = 0.0;
|
||||||
|
flashTimer->stop();
|
||||||
|
}
|
||||||
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerTarget::PlayerTarget(PlayerLogic *_owner, QGraphicsItem *parentItem)
|
PlayerTarget::PlayerTarget(PlayerLogic *_owner, QGraphicsItem *parentItem)
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,22 @@
|
||||||
#include <QPixmap>
|
#include <QPixmap>
|
||||||
|
|
||||||
class PlayerLogic;
|
class PlayerLogic;
|
||||||
|
class QTimer;
|
||||||
|
|
||||||
class PlayerCounter : public AbstractCounter
|
class PlayerCounter : public AbstractCounter
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
protected:
|
||||||
|
void onValueChanged(int oldValue, int newValue) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTimer *flashTimer = nullptr;
|
||||||
|
qreal flashAlpha = 0.0;
|
||||||
|
int flashDelta = 0;
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void flashTick();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PlayerCounter(CounterState *state, PlayerLogic *player, QGraphicsItem *parent);
|
PlayerCounter(CounterState *state, PlayerLogic *player, QGraphicsItem *parent);
|
||||||
QRectF boundingRect() const override;
|
QRectF boundingRect() const override;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
|
|
||||||
#include <QGraphicsScene>
|
#include <QGraphicsScene>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
#include <QTimer>
|
||||||
#include <libcockatrice/card/card_info.h>
|
#include <libcockatrice/card/card_info.h>
|
||||||
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
|
#include <libcockatrice/protocol/pb/command_move_card.pb.h>
|
||||||
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
#include <libcockatrice/protocol/pb/command_set_card_attr.pb.h>
|
||||||
|
|
@ -47,6 +48,31 @@ void TableZone::updateBg()
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TableZone::triggerDamageShimmer()
|
||||||
|
{
|
||||||
|
// design-game: damage pulses the affected zone with a brief crimson
|
||||||
|
// shimmer so a hit reads as an event, not a dialog.
|
||||||
|
if (!SettingsCache::instance().userInterface().getAnimationsEnabled() ||
|
||||||
|
!SettingsCache::instance().userInterface().getBattlefieldFlashEnabled()) {
|
||||||
|
damageShimmerAlpha = 0.0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
damageShimmerAlpha = 1.0;
|
||||||
|
if (damageShimmerTimer == nullptr) {
|
||||||
|
damageShimmerTimer = new QTimer(this);
|
||||||
|
connect(damageShimmerTimer, &QTimer::timeout, this, [this] {
|
||||||
|
damageShimmerAlpha -= 0.12;
|
||||||
|
if (damageShimmerAlpha <= 0.0) {
|
||||||
|
damageShimmerAlpha = 0.0;
|
||||||
|
damageShimmerTimer->stop();
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
damageShimmerTimer->start(50);
|
||||||
|
}
|
||||||
|
|
||||||
QRectF TableZone::boundingRect() const
|
QRectF TableZone::boundingRect() const
|
||||||
{
|
{
|
||||||
return QRectF(0, 0, width, height);
|
return QRectF(0, 0, width, height);
|
||||||
|
|
@ -77,6 +103,13 @@ void TableZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*opti
|
||||||
painter->fillRect(boundingRect(), FADE_MASK);
|
painter->fillRect(boundingRect(), FADE_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decaying crimson wash from taking damage.
|
||||||
|
if (damageShimmerAlpha > 0.0) {
|
||||||
|
QColor shimmerColor(239, 68, 68);
|
||||||
|
shimmerColor.setAlphaF(0.22 * damageShimmerAlpha);
|
||||||
|
painter->fillRect(boundingRect(), shimmerColor);
|
||||||
|
}
|
||||||
|
|
||||||
paintLandDivider(painter);
|
paintLandDivider(painter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,8 @@
|
||||||
#include "../board/abstract_card_item.h"
|
#include "../board/abstract_card_item.h"
|
||||||
#include "select_zone.h"
|
#include "select_zone.h"
|
||||||
|
|
||||||
|
class QTimer;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief TableZone is the grid based rect where CardItems may be placed.
|
* @brief TableZone is the grid based rect where CardItems may be placed.
|
||||||
*
|
*
|
||||||
|
|
@ -184,10 +186,21 @@ public:
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
Flashes the table surface after a player loses life.
|
||||||
|
|
||||||
|
Wired up through AbstractCounter so the life total on the battlefield
|
||||||
|
glows when it changes.
|
||||||
|
*/
|
||||||
|
void triggerDamageShimmer();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void paintZoneOutline(QPainter *painter);
|
void paintZoneOutline(QPainter *painter);
|
||||||
void paintLandDivider(QPainter *painter);
|
void paintLandDivider(QPainter *painter);
|
||||||
|
|
||||||
|
QTimer *damageShimmerTimer = nullptr;
|
||||||
|
qreal damageShimmerAlpha = 0.0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Calculates card stack widths so mapping functions work properly
|
Calculates card stack widths so mapping functions work properly
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@
|
||||||
|
|
||||||
bool ThemeConfig::isEmpty() const
|
bool ThemeConfig::isEmpty() const
|
||||||
{
|
{
|
||||||
return colorScheme.isEmpty() && styleName.isEmpty();
|
return colorScheme.isEmpty() && styleName.isEmpty() && displayFont.isEmpty() && bodyFont.isEmpty() &&
|
||||||
|
cardTitleFont.isEmpty() && monoFont.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString ThemeConfig::toIni() const
|
QString ThemeConfig::toIni() const
|
||||||
|
|
@ -17,6 +18,21 @@ QString ThemeConfig::toIni() const
|
||||||
out += QString("ColorScheme = %1\n").arg(colorScheme.isEmpty() ? "System" : colorScheme);
|
out += QString("ColorScheme = %1\n").arg(colorScheme.isEmpty() ? "System" : colorScheme);
|
||||||
out += "\n[Style]\n";
|
out += "\n[Style]\n";
|
||||||
out += QString("Name = %1\n").arg(styleName.isEmpty() ? "Default" : styleName);
|
out += QString("Name = %1\n").arg(styleName.isEmpty() ? "Default" : styleName);
|
||||||
|
if (!displayFont.isEmpty() || !bodyFont.isEmpty() || !cardTitleFont.isEmpty() || !monoFont.isEmpty()) {
|
||||||
|
out += "\n[Typography]\n";
|
||||||
|
if (!displayFont.isEmpty()) {
|
||||||
|
out += QString("DisplayFont = %1\n").arg(displayFont);
|
||||||
|
}
|
||||||
|
if (!bodyFont.isEmpty()) {
|
||||||
|
out += QString("BodyFont = %1\n").arg(bodyFont);
|
||||||
|
}
|
||||||
|
if (!cardTitleFont.isEmpty()) {
|
||||||
|
out += QString("CardTitleFont = %1\n").arg(cardTitleFont);
|
||||||
|
}
|
||||||
|
if (!monoFont.isEmpty()) {
|
||||||
|
out += QString("MonoFont = %1\n").arg(monoFont);
|
||||||
|
}
|
||||||
|
}
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -65,6 +81,16 @@ ThemeConfig ThemeConfig::fromThemeDir(const QString &themeDirPath)
|
||||||
if (key.compare("Name", Qt::CaseInsensitive) == 0) {
|
if (key.compare("Name", Qt::CaseInsensitive) == 0) {
|
||||||
cfg.styleName = value;
|
cfg.styleName = value;
|
||||||
}
|
}
|
||||||
|
} else if (currentSection.compare("Typography", Qt::CaseInsensitive) == 0) {
|
||||||
|
if (key.compare("DisplayFont", Qt::CaseInsensitive) == 0) {
|
||||||
|
cfg.displayFont = value;
|
||||||
|
} else if (key.compare("BodyFont", Qt::CaseInsensitive) == 0) {
|
||||||
|
cfg.bodyFont = value;
|
||||||
|
} else if (key.compare("CardTitleFont", Qt::CaseInsensitive) == 0) {
|
||||||
|
cfg.cardTitleFont = value;
|
||||||
|
} else if (key.compare("MonoFont", Qt::CaseInsensitive) == 0) {
|
||||||
|
cfg.monoFont = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,13 @@ struct ThemeConfig
|
||||||
QString colorScheme;
|
QString colorScheme;
|
||||||
QString styleName;
|
QString styleName;
|
||||||
|
|
||||||
|
// Optional per-theme font families (see design-game.md). Empty = use the
|
||||||
|
// application default / the classic "Serif" hint for card titles.
|
||||||
|
QString displayFont;
|
||||||
|
QString bodyFont;
|
||||||
|
QString cardTitleFont;
|
||||||
|
QString monoFont;
|
||||||
|
|
||||||
bool isEmpty() const;
|
bool isEmpty() const;
|
||||||
QString toIni() const;
|
QString toIni() const;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,8 @@ ThemeManager::ThemeManager(QObject *parent) : QObject(parent)
|
||||||
}
|
}
|
||||||
// Capture the untouched application palette before any theme is applied.
|
// Capture the untouched application palette before any theme is applied.
|
||||||
defaultPalette = qApp->palette();
|
defaultPalette = qApp->palette();
|
||||||
|
// Capture the untouched application font before any theme is applied.
|
||||||
|
defaultFont = qApp->font();
|
||||||
ensureThemeDirectoryExists();
|
ensureThemeDirectoryExists();
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
|
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
|
||||||
connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, [this] {
|
connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, [this] {
|
||||||
|
|
@ -352,6 +354,16 @@ void ThemeManager::applyStyleAndPalette(const QString &themeName,
|
||||||
// widget gets polished against the stale colours, requiring a second apply
|
// widget gets polished against the stale colours, requiring a second apply
|
||||||
// to fully resolve. Setting palette first means setStyle's repolish cascade
|
// to fully resolve. Setting palette first means setStyle's repolish cascade
|
||||||
// already sees the correct colours.
|
// already sees the correct colours.
|
||||||
|
// The body font is applied on the same pass, before the repolish, so
|
||||||
|
// widgets are polished with the theme's typeface.
|
||||||
|
currentThemeConfig = themeCfg;
|
||||||
|
if (!themeCfg.bodyFont.isEmpty()) {
|
||||||
|
QFont bodyFont(themeCfg.bodyFont);
|
||||||
|
bodyFont.setStyleHint(QFont::SansSerif);
|
||||||
|
qApp->setFont(bodyFont);
|
||||||
|
} else {
|
||||||
|
qApp->setFont(defaultFont);
|
||||||
|
}
|
||||||
qApp->setPalette(base);
|
qApp->setPalette(base);
|
||||||
qApp->setStyle(style);
|
qApp->setStyle(style);
|
||||||
|
|
||||||
|
|
@ -475,3 +487,50 @@ QBrush ThemeManager::getExtraBgBrush(Role role, int zoneId)
|
||||||
|
|
||||||
return brushCache.value(zoneId);
|
return brushCache.value(zoneId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QFont ThemeManager::cardTitleFont() const
|
||||||
|
{
|
||||||
|
QFont font;
|
||||||
|
if (currentThemeConfig.cardTitleFont.isEmpty()) {
|
||||||
|
// Classic behaviour: the platform serif, echoing printed cardstock.
|
||||||
|
font.setFamily(QStringLiteral("Serif"));
|
||||||
|
font.setStyleHint(QFont::Serif);
|
||||||
|
} else {
|
||||||
|
font.setFamily(currentThemeConfig.cardTitleFont);
|
||||||
|
}
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFont ThemeManager::monoFont() const
|
||||||
|
{
|
||||||
|
QFont font;
|
||||||
|
if (currentThemeConfig.monoFont.isEmpty()) {
|
||||||
|
// Classic behaviour: serif numerals on counters and the card back.
|
||||||
|
font.setFamily(QStringLiteral("Serif"));
|
||||||
|
font.setStyleHint(QFont::Serif);
|
||||||
|
} else {
|
||||||
|
font.setFamily(currentThemeConfig.monoFont);
|
||||||
|
font.setStyleHint(QFont::Monospace);
|
||||||
|
}
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
QFont ThemeManager::displayFont() const
|
||||||
|
{
|
||||||
|
QFont font;
|
||||||
|
if (currentThemeConfig.displayFont.isEmpty()) {
|
||||||
|
font.setFamily(QStringLiteral("sans-serif"));
|
||||||
|
font.setStyleHint(QFont::SansSerif);
|
||||||
|
} else {
|
||||||
|
font.setFamily(currentThemeConfig.displayFont);
|
||||||
|
}
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString ThemeManager::monoFontFamily() const
|
||||||
|
{
|
||||||
|
if (!currentThemeConfig.monoFont.isEmpty()) {
|
||||||
|
return currentThemeConfig.monoFont;
|
||||||
|
}
|
||||||
|
return QStringLiteral("monospace");
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@
|
||||||
|
|
||||||
#include <QBrush>
|
#include <QBrush>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QFont>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
@ -47,6 +48,12 @@ private:
|
||||||
// palette is applied. Used as the base when a theme supplies no palette, so
|
// palette is applied. Used as the base when a theme supplies no palette, so
|
||||||
// switching away from a custom palette restores the original colours.
|
// switching away from a custom palette restores the original colours.
|
||||||
QPalette defaultPalette;
|
QPalette defaultPalette;
|
||||||
|
// Pristine application font captured at startup, restored when the active
|
||||||
|
// theme declares no body font of its own.
|
||||||
|
QFont defaultFont;
|
||||||
|
// ThemeConfig of the currently applied theme, used to resolve per-theme
|
||||||
|
// typography tokens.
|
||||||
|
ThemeConfig currentThemeConfig;
|
||||||
QString currentThemePath;
|
QString currentThemePath;
|
||||||
std::array<QBrush, Role::MaxRole + 1> brushes;
|
std::array<QBrush, Role::MaxRole + 1> brushes;
|
||||||
QStringMap availableThemes;
|
QStringMap availableThemes;
|
||||||
|
|
@ -92,6 +99,14 @@ public:
|
||||||
|
|
||||||
QBrush &getBgBrush(Role zone);
|
QBrush &getBgBrush(Role zone);
|
||||||
QBrush getExtraBgBrush(Role zone, int zoneId = 0);
|
QBrush getExtraBgBrush(Role zone, int zoneId = 0);
|
||||||
|
|
||||||
|
// Per-theme typography helpers (see design-game.md). Falls back to the
|
||||||
|
// classic app defaults when the active theme declares no fonts, so
|
||||||
|
// non-CockatriceNG themes keep their current look.
|
||||||
|
QFont cardTitleFont() const;
|
||||||
|
QFont monoFont() const;
|
||||||
|
QFont displayFont() const;
|
||||||
|
QString monoFontFamily() const;
|
||||||
protected slots:
|
protected slots:
|
||||||
void themeChangedSlot();
|
void themeChangedSlot();
|
||||||
signals:
|
signals:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue