mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 09:33:25 -08:00
Compare commits
17 commits
159485bc46
...
8c2bfc46ff
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8c2bfc46ff | ||
|
|
69f4fb02db | ||
|
|
37b9544ca3 | ||
|
|
3daefe074c | ||
|
|
755fa38d96 | ||
|
|
71fd913058 | ||
|
|
9cb33f8fe4 | ||
|
|
dd15c1a5f9 | ||
|
|
d4f0b75e87 | ||
|
|
6b566af94e | ||
|
|
66405e966b | ||
|
|
dfef59ca4e | ||
|
|
15655767a8 | ||
|
|
c78fd1e06c | ||
|
|
77e9b92c5a | ||
|
|
d854bdfd83 | ||
|
|
3def6b00ef |
97 changed files with 2251 additions and 172 deletions
|
|
@ -154,6 +154,7 @@ set(cockatrice_SOURCES
|
|||
src/interface/palette_editor/palette_generator.cpp
|
||||
src/interface/palette_editor/quick_setup_panel.cpp
|
||||
src/interface/palette_editor/palette_grid_widget.cpp
|
||||
src/interface/palette_editor/font_grid_widget.cpp
|
||||
src/interface/palette_editor/palette_editor_dialog.cpp
|
||||
src/interface/widgets/cards/additional_info/color_identity_widget.cpp
|
||||
src/interface/widgets/cards/additional_info/deck_color_identity.cpp
|
||||
|
|
|
|||
|
|
@ -137,6 +137,9 @@ SettingsCache::SettingsCache()
|
|||
// before that rename (idempotent, safe to run on every startup, portable builds included).
|
||||
SettingsMigration::migrateGameFiltersToCamelCase(settingsPath);
|
||||
|
||||
// Retire appearance/maxFontSize into per-theme CardText max (idempotent, safe every startup).
|
||||
SettingsMigration::migrateAppearanceMaxFontSizeToTheme(settingsPath);
|
||||
|
||||
shortcutsSettings = new ShortcutsSettings(settingsPath, this);
|
||||
cardDatabaseSettings = new CardDatabaseSettings(settingsPath, this);
|
||||
serversSettings = new ServersSettings(settingsPath, this);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "shortcut_treeview.h"
|
||||
|
||||
#include "../../interface/theme_manager.h"
|
||||
#include "cache_settings.h"
|
||||
#include "shortcuts_settings.h"
|
||||
|
||||
|
|
@ -78,6 +79,18 @@ ShortcutTreeView::ShortcutTreeView(QWidget *parent) : QTreeView(parent)
|
|||
|
||||
connect(&SettingsCache::instance().shortcuts(), &ShortcutsSettings::shortCutChanged, this,
|
||||
&ShortcutTreeView::refreshShortcuts);
|
||||
|
||||
// Group headers store their font on the item; re-apply the role family on
|
||||
// font changes (setFont emits itemChanged, which repaints the rows).
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, [this] {
|
||||
QFont groupFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
groupFont.setBold(true);
|
||||
for (int row = 0; row < shortcutsModel->rowCount(); ++row) {
|
||||
if (auto *groupItem = shortcutsModel->item(row)) {
|
||||
groupItem->setFont(groupFont);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void ShortcutTreeView::populateShortcutsModel()
|
||||
|
|
@ -93,7 +106,8 @@ void ShortcutTreeView::populateShortcutsModel()
|
|||
curParent = parentItems.value(group);
|
||||
} else {
|
||||
curParent = new QStandardItem(group);
|
||||
static QFont font = curParent->font();
|
||||
// Family comes from the InterfaceDefault theme role; bold stays caller-side.
|
||||
QFont font = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
font.setBold(true);
|
||||
curParent->setFont(font);
|
||||
parentItems.insert(group, curParent);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "filter_tree_model.h"
|
||||
|
||||
#include "../interface/theme_manager.h"
|
||||
|
||||
#include <QFlags>
|
||||
#include <QFont>
|
||||
#include <QString>
|
||||
|
|
@ -39,6 +41,12 @@ FilterTreeModel::FilterTreeModel(QObject *parent) : QAbstractItemModel(parent)
|
|||
connect(fTree, &FilterTree::postInsertRow, this, &FilterTreeModel::proxyEndInsertRow);
|
||||
connect(fTree, &FilterTree::preRemoveRow, this, &FilterTreeModel::proxyBeginRemoveRow);
|
||||
connect(fTree, &FilterTree::postRemoveRow, this, &FilterTreeModel::proxyEndRemoveRow);
|
||||
// FontRole data reads the DeckList role live; rebroadcast so attached
|
||||
// views re-query instead of waiting for an incidental repaint.
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, [this] {
|
||||
emit layoutAboutToBeChanged();
|
||||
emit layoutChanged();
|
||||
});
|
||||
}
|
||||
|
||||
FilterTreeModel::~FilterTreeModel()
|
||||
|
|
@ -202,7 +210,8 @@ QVariant FilterTreeModel::data(const QModelIndex &index, int role) const
|
|||
switch (role) {
|
||||
case Qt::FontRole:
|
||||
if (!node->isLeaf()) {
|
||||
QFont f;
|
||||
// Family comes from the DeckList theme role; bold stays caller-side.
|
||||
QFont f = themeManager->appFont(AppFont::DeckList);
|
||||
f.setBold(true);
|
||||
return f;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../interface/card_localization.h"
|
||||
#include "../../interface/card_picture_loader/card_picture_loader.h"
|
||||
#include "../../interface/theme_manager.h"
|
||||
#include "../card_dimensions.h"
|
||||
#include "../game_scene.h"
|
||||
#include "../z_values.h"
|
||||
|
|
@ -34,7 +35,6 @@
|
|||
#include <QVariant>
|
||||
#include <QtGlobal>
|
||||
#include <algorithm>
|
||||
#include <libcockatrice/settings/appearance_settings.h>
|
||||
#include <libcockatrice/settings/cards_display_settings.h>
|
||||
#include <libcockatrice/settings/debug_settings.h>
|
||||
#include <qnamespace.h>
|
||||
|
|
@ -143,8 +143,8 @@ QSizeF AbstractCardItem::getTranslatedSize(QPainter *painter) const
|
|||
|
||||
void AbstractCardItem::transformPainter(QPainter *painter, const QSizeF &translatedSize, int angle)
|
||||
{
|
||||
const int MAX_FONT_SIZE = SettingsCache::instance().appearance().getMaxFontSize();
|
||||
const int fontSize = std::max(9, MAX_FONT_SIZE);
|
||||
const int minSize = std::max(1, themeManager->cardTextMinSize());
|
||||
const int fontSize = std::max(minSize, std::max(1, themeManager->cardTextMaxSize()));
|
||||
|
||||
QRectF totalBoundingRect = painter->combinedTransform().mapRect(boundingRect());
|
||||
|
||||
|
|
@ -154,7 +154,7 @@ void AbstractCardItem::transformPainter(QPainter *painter, const QSizeF &transla
|
|||
painter->rotate(angle);
|
||||
painter->translate(-translatedSize.width() / 2, -translatedSize.height() / 2);
|
||||
|
||||
QFont f;
|
||||
QFont f = themeManager->appFont(AppFont::CardText);
|
||||
f.setPixelSize(fontSize * scale);
|
||||
|
||||
painter->setFont(f);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "abstract_graphics_item.h"
|
||||
|
||||
#include "../../interface/theme_manager.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QFont>
|
||||
#include <QFontMetrics>
|
||||
|
|
@ -20,7 +22,7 @@ void AbstractGraphicsItem::paintNumberEllipse(int number,
|
|||
painter->save();
|
||||
|
||||
QString numStr = QString::number(number);
|
||||
QFont font("Serif");
|
||||
QFont font = themeManager->cardTextFont();
|
||||
font.setPixelSize(fontSize);
|
||||
font.setWeight(QFont::Bold);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "counter_general.h"
|
||||
|
||||
#include "../../interface/pixel_map_generator.h"
|
||||
#include "../../interface/theme_manager.h"
|
||||
#include "abstract_graphics_item.h"
|
||||
|
||||
#include <QFont>
|
||||
|
|
@ -41,7 +42,7 @@ void GeneralCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /
|
|||
painter->drawPixmap(QPoint(0, 0), pixmap);
|
||||
|
||||
if (value) {
|
||||
QFont f("Serif");
|
||||
QFont f = themeManager->cardTextFont();
|
||||
f.setPixelSize(qMax((int)(radius * scaleFactor), 10));
|
||||
f.setWeight(QFont::Bold);
|
||||
painter->setPen(Qt::black);
|
||||
|
|
|
|||
|
|
@ -240,8 +240,8 @@ void DeckViewCardContainer::paint(QPainter *painter, const QStyleOptionGraphicsI
|
|||
painter->drawLine(QPointF(0, separatorY), QPointF(width, separatorY));
|
||||
|
||||
painter->setPen(QColor(Qt::white));
|
||||
QFont f("Serif");
|
||||
f.setStyleHint(QFont::Serif);
|
||||
// Family comes from the DeckList theme role; pixel sizes/weights unchanged.
|
||||
QFont f = themeManager->deckListFont();
|
||||
f.setPixelSize(24);
|
||||
f.setWeight(QFont::Bold);
|
||||
painter->setFont(f);
|
||||
|
|
@ -292,8 +292,8 @@ QList<QPair<int, int>> DeckViewCardContainer::getRowsAndCols() const
|
|||
|
||||
int DeckViewCardContainer::getCardTypeTextWidth() const
|
||||
{
|
||||
QFont f("Serif");
|
||||
f.setStyleHint(QFont::Serif);
|
||||
// Family comes from the DeckList theme role; pixel size/weight unchanged.
|
||||
QFont f = themeManager->deckListFont();
|
||||
f.setPixelSize(16);
|
||||
f.setWeight(QFont::Bold);
|
||||
QFontMetrics fm(f);
|
||||
|
|
@ -366,6 +366,15 @@ void DeckViewCardContainer::setWidth(qreal _width)
|
|||
|
||||
DeckViewScene::DeckViewScene(QObject *parent) : QGraphicsScene(parent), locked(true), deck(0), optimalAspectRatio(1.0)
|
||||
{
|
||||
// Zone headers read the DeckList role at paint time and cache their
|
||||
// rendering, so touch every item to invalidate the caches and pick up the
|
||||
// new family on font changes (containers cannot connect this themselves:
|
||||
// QGraphicsItem is not a QObject).
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, [this] {
|
||||
for (auto *item : items()) {
|
||||
item->update();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
DeckViewScene::~DeckViewScene()
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "game_scene.h"
|
||||
|
||||
#include "../client/settings/cache_settings.h"
|
||||
#include "../interface/theme_manager.h"
|
||||
#include "animated_item.h"
|
||||
#include "board/abstract_card_item.h"
|
||||
#include "board/arrow_item.h"
|
||||
|
|
@ -64,6 +65,14 @@ GameScene::GameScene(PhasesToolbar *_phasesToolbar, QObject *parent)
|
|||
addItem(phasesToolbar);
|
||||
connect(&SettingsCache::instance().userInterface(), &InterfaceSettings::minPlayersForMultiColumnLayoutChanged, this,
|
||||
&GameScene::rearrange);
|
||||
// CardText items (P/T boxes, counters, player names) read the role at
|
||||
// paint time and cache their rendering, so touch every item to invalidate
|
||||
// the caches and pick up the new family on font changes.
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, [this] {
|
||||
for (auto *item : items()) {
|
||||
item->update();
|
||||
}
|
||||
});
|
||||
|
||||
rearrange();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
#include "../client/settings/cache_settings.h"
|
||||
#include "../client/settings/shortcuts_settings.h"
|
||||
#include "../interface/theme_manager.h"
|
||||
#include "game_scene.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
#include <QEvent>
|
||||
#include <QFont>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
|
|
@ -24,6 +26,21 @@
|
|||
#include <libcockatrice/utility/qt_utils.h>
|
||||
#include <qnamespace.h>
|
||||
|
||||
namespace
|
||||
{
|
||||
QFont deckOverlayFont(int pixelSize, bool bold)
|
||||
{
|
||||
// The drag/total counters and the tally columns are in-game overlays, not
|
||||
// deck list text: keep the monospace family the stylesheets used to set so
|
||||
// digit widths stay stable as counts tick and `white-space: pre` lines up.
|
||||
QFont font(QStringLiteral("monospace"));
|
||||
font.setStyleHint(QFont::Monospace);
|
||||
font.setPixelSize(pixelSize);
|
||||
font.setBold(bold);
|
||||
return font;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// QRubberBand calls raise() in showEvent() and changeEvent() to stay on top of siblings.
|
||||
// This subclass disables that behavior so dragCountLabel can appear above it.
|
||||
class SelectionRubberBand : public QRubberBand
|
||||
|
|
@ -75,15 +92,14 @@ GameView::GameView(GameScene *scene, QWidget *parent) : QGraphicsView(scene, par
|
|||
rubberBand = new SelectionRubberBand(QRubberBand::Rectangle, this);
|
||||
|
||||
const QString baseProperties = "color: white; "
|
||||
"font-family: monospace; "
|
||||
"background-color: rgba(0, 0, 0, 160); "
|
||||
"border-radius: 3px; "
|
||||
"padding: 1px 2px; "
|
||||
"white-space: pre;";
|
||||
|
||||
const QString dragCountLabelStyle = baseProperties + "font-size: 14px; font-weight: bold;";
|
||||
const QString totalCountLabelStyle = baseProperties + "font-size: 16px; font-weight: bold;";
|
||||
const QString subtypeTallyLabelStyle = baseProperties + "font-size: 12px;";
|
||||
const QString dragCountLabelStyle = baseProperties;
|
||||
const QString totalCountLabelStyle = baseProperties;
|
||||
const QString subtypeTallyLabelStyle = baseProperties;
|
||||
|
||||
dragCountLabel = new QLabel(this);
|
||||
dragCountLabel->setStyleSheet(dragCountLabelStyle);
|
||||
|
|
@ -100,6 +116,27 @@ GameView::GameView(GameScene *scene, QWidget *parent) : QGraphicsView(scene, par
|
|||
tallyLayout->setContentsMargins(2, 2, 2, 2);
|
||||
tallyLayout->setSpacing(2);
|
||||
tallyContainer->hide();
|
||||
|
||||
applyDeckOverlayFonts();
|
||||
}
|
||||
|
||||
void GameView::applyDeckOverlayFonts()
|
||||
{
|
||||
dragCountLabel->setFont(deckOverlayFont(14, true));
|
||||
totalCountLabel->setFont(deckOverlayFont(16, true));
|
||||
tallyContainer->setFont(deckOverlayFont(12, false));
|
||||
for (int i = 0; i < tallyLayout->count(); ++i) {
|
||||
if (auto *label = qobject_cast<QLabel *>(tallyLayout->itemAt(i)->widget())) {
|
||||
// Count column (odd positions) keeps the bold emphasis.
|
||||
const bool count = i % 2 == 1;
|
||||
label->setFont(deckOverlayFont(count ? 14 : 12, count));
|
||||
}
|
||||
}
|
||||
|
||||
// The container keeps the size computed from the previous fonts, so force
|
||||
// rebuildTallyLabels() to re-measure it instead of reusing cachedTallyRows.
|
||||
cachedTallyRows.clear();
|
||||
updateTotalSelectionCount();
|
||||
}
|
||||
|
||||
void GameView::resizeEvent(QResizeEvent *event)
|
||||
|
|
@ -219,9 +256,8 @@ QSize GameView::rebuildTallyLabels(const QList<TallyRow> &entries)
|
|||
{
|
||||
clearTallyLabels();
|
||||
|
||||
const QString nameStyle = QStringLiteral("color: white; font-size: 12px; background: transparent;");
|
||||
const QString countStyle =
|
||||
QStringLiteral("color: white; font-size: 14px; font-weight: bold; background: transparent;");
|
||||
const QString nameStyle = QStringLiteral("color: white; background: transparent;");
|
||||
const QString countStyle = QStringLiteral("color: white; background: transparent;");
|
||||
|
||||
int totalHeight = 0;
|
||||
int maxNameWidth = 0;
|
||||
|
|
@ -231,11 +267,13 @@ QSize GameView::rebuildTallyLabels(const QList<TallyRow> &entries)
|
|||
for (const TallyRow &entry : entries) {
|
||||
auto *nameLabel = new QLabel(entry.name, tallyContainer);
|
||||
nameLabel->setStyleSheet(nameStyle);
|
||||
nameLabel->setFont(deckOverlayFont(12, false));
|
||||
nameLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
tallyLayout->addWidget(nameLabel, row, 0);
|
||||
|
||||
auto *countLabel = new QLabel(entry.value, tallyContainer);
|
||||
countLabel->setStyleSheet(countStyle);
|
||||
countLabel->setFont(deckOverlayFont(14, true));
|
||||
countLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
|
||||
tallyLayout->addWidget(countLabel, row, 1);
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@ private slots:
|
|||
void refreshShortcuts();
|
||||
void updateTotalSelectionCount(const QSize &viewSize = QSize());
|
||||
void setFocusDisabled(bool disabled);
|
||||
void applyDeckOverlayFonts();
|
||||
public slots:
|
||||
void updateSceneRect(const QRectF &rect);
|
||||
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "../../client/settings/cache_settings.h"
|
||||
#include "../../interface/pixel_map_generator.h"
|
||||
#include "../../interface/theme_manager.h"
|
||||
#include "../board/abstract_counter.h"
|
||||
#include "../board/abstract_graphics_item.h"
|
||||
#include "../board/arrow_target.h"
|
||||
|
|
@ -76,7 +77,7 @@ void PlayerCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*
|
|||
|
||||
QRectF translatedRect = path.controlPointRect();
|
||||
QSize translatedSize = translatedRect.size().toSize();
|
||||
QFont font("Serif");
|
||||
QFont font = themeManager->cardTextFont();
|
||||
font.setWeight(QFont::Bold);
|
||||
font.setPixelSize(qMax(qRound(translatedSize.height() / 1.3), 9));
|
||||
painter->setFont(font);
|
||||
|
|
@ -226,7 +227,7 @@ void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*o
|
|||
name = name.mid(0, 10) + "...";
|
||||
}
|
||||
|
||||
QFont font;
|
||||
QFont font = themeManager->appFont(AppFont::CardText);
|
||||
font.setPixelSize(qMax(qRound(translatedNameRect.height() / 1.5), 9));
|
||||
painter->setFont(font);
|
||||
painter->setPen(Qt::white);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "deck_loader.h"
|
||||
|
||||
#include "../theme_manager.h"
|
||||
#include "libcockatrice/card/card_info.h"
|
||||
#include "libcockatrice/card/database/card_database_querier.h"
|
||||
#include "libcockatrice/deck_list/tree/abstract_deck_list_card_node.h"
|
||||
|
|
@ -579,6 +580,8 @@ void DeckLoader::printDeckListNode(QTextCursor *cursor, const InnerDecklistNode
|
|||
if (!cards.isEmpty()) {
|
||||
QTextBlockFormat blockFormat;
|
||||
QTextCharFormat charFormat;
|
||||
// Family comes from the DeckList theme role; sizes/weights unchanged.
|
||||
charFormat.setFontFamilies({themeManager->deckListFont().family()});
|
||||
charFormat.setFontPointSize(11);
|
||||
charFormat.setFontWeight(QFont::Bold);
|
||||
cursor->insertBlock(blockFormat, charFormat);
|
||||
|
|
@ -592,6 +595,7 @@ void DeckLoader::printDeckListNode(QTextCursor *cursor, const InnerDecklistNode
|
|||
const AbstractDecklistCardNode *card = cards[i];
|
||||
|
||||
QTextCharFormat cellCharFormat;
|
||||
cellCharFormat.setFontFamilies({themeManager->deckListFont().family()});
|
||||
cellCharFormat.setFontPointSize(9);
|
||||
|
||||
QTextTableCell cell = table->cellAt(i, 0);
|
||||
|
|
@ -613,6 +617,7 @@ void DeckLoader::printDeckListNode(QTextCursor *cursor, const InnerDecklistNode
|
|||
|
||||
QTextBlockFormat blockFormat;
|
||||
QTextCharFormat charFormat;
|
||||
charFormat.setFontFamilies({themeManager->deckListFont().family()});
|
||||
charFormat.setFontPointSize(14);
|
||||
charFormat.setFontWeight(QFont::Bold);
|
||||
|
||||
|
|
@ -640,14 +645,18 @@ void DeckLoader::printDeckList(QPrinter *printer, const DeckList &deckList)
|
|||
{
|
||||
QTextDocument doc;
|
||||
|
||||
QFont font("Serif");
|
||||
font.setStyleHint(QFont::Serif);
|
||||
// Family comes from the DeckList theme role; the print sizes/weights below stay unchanged.
|
||||
// Print output is a one-shot snapshot and intentionally does not subscribe
|
||||
// to fontsChanged (there is no live view to repaint); reprinting picks up
|
||||
// the current role font.
|
||||
QFont font = themeManager->deckListFont();
|
||||
doc.setDefaultFont(font);
|
||||
|
||||
QTextCursor cursor(&doc);
|
||||
|
||||
QTextBlockFormat headerBlockFormat;
|
||||
QTextCharFormat headerCharFormat;
|
||||
headerCharFormat.setFontFamilies({themeManager->deckListFont().family()});
|
||||
headerCharFormat.setFontPointSize(16);
|
||||
headerCharFormat.setFontWeight(QFont::Bold);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "color_button.h"
|
||||
|
||||
#include "../theme_manager.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QColorDialog>
|
||||
#include <QFont>
|
||||
|
|
@ -21,6 +23,7 @@ ColorButton::ColorButton(QWidget *parent) : QToolButton(parent)
|
|||
setCursor(Qt::PointingHandCursor);
|
||||
setToolTip(tr("Click to pick a color"));
|
||||
connect(this, &QToolButton::clicked, this, &ColorButton::pickColor);
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, &ColorButton::updateSwatch);
|
||||
}
|
||||
|
||||
void ColorButton::setColor(const QColor &c)
|
||||
|
|
@ -73,7 +76,8 @@ void ColorButton::updateSwatch()
|
|||
// Hex label — black or white for contrast
|
||||
int luma = 0.299 * color.red() + 0.587 * color.green() + 0.114 * color.blue();
|
||||
painter.setPen((luma > 128 && color.alpha() > 80) ? QColor(0, 0, 0, 180) : QColor(255, 255, 255, 200));
|
||||
QFont f = font();
|
||||
// Family comes from the InterfaceDefault theme role; the 8px size stays caller-side.
|
||||
QFont f = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
f.setPixelSize(8);
|
||||
painter.setFont(f);
|
||||
painter.drawText(rect(), Qt::AlignCenter, color.name().toUpper());
|
||||
|
|
|
|||
208
cockatrice/src/interface/palette_editor/font_grid_widget.cpp
Normal file
208
cockatrice/src/interface/palette_editor/font_grid_widget.cpp
Normal file
|
|
@ -0,0 +1,208 @@
|
|||
#include "font_grid_widget.h"
|
||||
|
||||
#include "../theme_manager.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFont>
|
||||
#include <QFontComboBox>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QMetaEnum>
|
||||
#include <QSpinBox>
|
||||
#include <QtGlobal>
|
||||
|
||||
static constexpr int MIN_FONT_SIZE = 6;
|
||||
static constexpr int MAX_FONT_SIZE = 72;
|
||||
static constexpr int CARD_TEXT_MIN_SIZE = 1;
|
||||
static constexpr int CARD_TEXT_MAX_SIZE = 12;
|
||||
static constexpr int FALLBACK_FONT_SIZE = 10;
|
||||
|
||||
static const QMap<AppFont::Role, const char *> APP_FONT_DESCRIPTIONS = {
|
||||
{AppFont::InterfaceDefault, QT_TR_NOOP("Default font for menus, dialogs and widgets")},
|
||||
{AppFont::ChatLog, QT_TR_NOOP("Font for chat messages and logs")},
|
||||
{AppFont::CardText, QT_TR_NOOP("Font for text rendered on cards")},
|
||||
{AppFont::DeckList, QT_TR_NOOP("Font for deck lists and the deck editor")},
|
||||
};
|
||||
|
||||
static QString roleDisplayName(AppFont::Role role)
|
||||
{
|
||||
switch (role) {
|
||||
case AppFont::InterfaceDefault:
|
||||
return FontGridWidget::tr("Interface default");
|
||||
case AppFont::ChatLog:
|
||||
return FontGridWidget::tr("Chat log");
|
||||
case AppFont::CardText:
|
||||
return FontGridWidget::tr("Card text");
|
||||
case AppFont::DeckList:
|
||||
return FontGridWidget::tr("Deck list");
|
||||
default:
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
FontGridWidget::FontGridWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
auto *grid = new QGridLayout(this);
|
||||
grid->setSpacing(3);
|
||||
grid->setContentsMargins(12, 8, 12, 8);
|
||||
grid->setColumnStretch(0, 0);
|
||||
grid->setColumnStretch(1, 1);
|
||||
grid->setColumnStretch(2, 0);
|
||||
grid->setColumnStretch(3, 0);
|
||||
|
||||
QMetaEnum fontEnum = QMetaEnum::fromType<AppFont::Role>();
|
||||
for (int i = 0; i < fontEnum.keyCount(); ++i) {
|
||||
auto role = static_cast<AppFont::Role>(fontEnum.value(i));
|
||||
|
||||
auto *label = new QLabel(this);
|
||||
grid->addWidget(label, i, 0);
|
||||
|
||||
auto *familyCombo = new QFontComboBox(this);
|
||||
grid->addWidget(familyCombo, i, 1);
|
||||
connect(familyCombo, &QFontComboBox::currentFontChanged, this, [this] { emit fontsChanged(); });
|
||||
|
||||
if (role == AppFont::CardText) {
|
||||
auto *minSpin = new QSpinBox(this);
|
||||
minSpin->setRange(CARD_TEXT_MIN_SIZE, MAX_FONT_SIZE);
|
||||
grid->addWidget(minSpin, i, 2);
|
||||
connect(minSpin, &QSpinBox::valueChanged, this, [this] { emit fontsChanged(); });
|
||||
|
||||
auto *maxSpin = new QSpinBox(this);
|
||||
maxSpin->setRange(MIN_FONT_SIZE, MAX_FONT_SIZE);
|
||||
grid->addWidget(maxSpin, i, 3);
|
||||
connect(maxSpin, &QSpinBox::valueChanged, this, [this] { emit fontsChanged(); });
|
||||
|
||||
// Keep the range consistent: otherwise min 20 / max 12 saves as-is
|
||||
// and cardTextMaxSize() silently clamps the max up to the min, so
|
||||
// the max spin shows a size that is never used. Moving one spin
|
||||
// pulls the other's bound along.
|
||||
connect(minSpin, &QSpinBox::valueChanged, this, [maxSpin](int value) { maxSpin->setMinimum(value); });
|
||||
connect(maxSpin, &QSpinBox::valueChanged, this, [minSpin](int value) { minSpin->setMaximum(value); });
|
||||
|
||||
label->setBuddy(familyCombo);
|
||||
|
||||
fontRows[role] = {label, familyCombo, maxSpin, minSpin};
|
||||
continue;
|
||||
}
|
||||
|
||||
auto *sizeSpin = new QSpinBox(this);
|
||||
sizeSpin->setRange(MIN_FONT_SIZE, MAX_FONT_SIZE);
|
||||
grid->addWidget(sizeSpin, i, 2);
|
||||
connect(sizeSpin, &QSpinBox::valueChanged, this, [this] { emit fontsChanged(); });
|
||||
|
||||
label->setBuddy(familyCombo);
|
||||
|
||||
fontRows[role] = {label, familyCombo, sizeSpin, nullptr};
|
||||
}
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void FontGridWidget::loadFonts(const FontConfig &cfg)
|
||||
{
|
||||
// Suppress fontsChanged while materializing fallback rows so the initial
|
||||
// load never reads as a user edit (mirrors paletteGrid blocking).
|
||||
blockSignals(true);
|
||||
QMetaEnum fontEnum = QMetaEnum::fromType<AppFont::Role>();
|
||||
for (int i = 0; i < fontEnum.keyCount(); ++i) {
|
||||
auto role = static_cast<AppFont::Role>(fontEnum.value(i));
|
||||
const FontRow &row = fontRows[role];
|
||||
|
||||
// Roles absent from the file resolve the same way the runtime does: an unset
|
||||
// role falls back to the config's InterfaceDefault, and only then to the
|
||||
// startup font. appFont() would return the live preview instead, so Reset and
|
||||
// a first load must not measure against it.
|
||||
const QFont fallback = cfg.fonts.value(AppFont::InterfaceDefault, themeManager->defaultAppFont(role));
|
||||
const QFont font = cfg.fonts.value(role, fallback);
|
||||
row.familyCombo->setCurrentFont(font);
|
||||
|
||||
if (role == AppFont::CardText && row.minSpin != nullptr) {
|
||||
// A previous load may have narrowed the linked bounds (min 20 pulls
|
||||
// max up to 20), which would clamp the values written below. Reset
|
||||
// both to the full range first; the valueChanged lambdas re-link
|
||||
// them as the values are set.
|
||||
row.minSpin->setRange(CARD_TEXT_MIN_SIZE, MAX_FONT_SIZE);
|
||||
row.sizeSpin->setRange(MIN_FONT_SIZE, MAX_FONT_SIZE);
|
||||
|
||||
// The max spin is a size-only override. Without CardTextMaxSize it
|
||||
// follows the CardText family size, and without CardText at all it
|
||||
// must match cardTextMaxSize()'s default rather than the system
|
||||
// startup size, which currentFontConfig() would otherwise bake in.
|
||||
const int fallbackMax = cfg.fonts.contains(role) ? font.pointSize() : CARD_TEXT_MAX_SIZE;
|
||||
int maxSize = cfg.cardTextMaxSize > 0 ? cfg.cardTextMaxSize : fallbackMax;
|
||||
if (maxSize <= 0) {
|
||||
maxSize = CARD_TEXT_MAX_SIZE;
|
||||
}
|
||||
int minSize = cfg.cardTextMinSize > 0 ? cfg.cardTextMinSize : themeManager->cardTextMinSize();
|
||||
minSize = qBound(CARD_TEXT_MIN_SIZE, minSize, MAX_FONT_SIZE);
|
||||
maxSize = qBound(MIN_FONT_SIZE, maxSize, MAX_FONT_SIZE);
|
||||
if (maxSize < minSize) {
|
||||
maxSize = minSize;
|
||||
}
|
||||
|
||||
// Max first, then min: each value re-applies the linked bound, so
|
||||
// the pair ends up consistent instead of clamping the smaller one.
|
||||
row.sizeSpin->setValue(maxSize);
|
||||
row.minSpin->setValue(minSize);
|
||||
continue;
|
||||
}
|
||||
|
||||
int size = font.pointSize();
|
||||
if (size <= 0) {
|
||||
size = qApp->font().pointSize();
|
||||
}
|
||||
if (size <= 0) {
|
||||
size = FALLBACK_FONT_SIZE;
|
||||
}
|
||||
row.sizeSpin->setValue(qBound(MIN_FONT_SIZE, size, MAX_FONT_SIZE));
|
||||
}
|
||||
blockSignals(false);
|
||||
}
|
||||
|
||||
FontConfig FontGridWidget::currentFontConfig() const
|
||||
{
|
||||
FontConfig cfg;
|
||||
QMetaEnum fontEnum = QMetaEnum::fromType<AppFont::Role>();
|
||||
for (int i = 0; i < fontEnum.keyCount(); ++i) {
|
||||
auto role = static_cast<AppFont::Role>(fontEnum.value(i));
|
||||
const FontRow &row = fontRows.value(role);
|
||||
|
||||
// Canonical family + point size only: a fresh QFont carries default
|
||||
// (non-bold, non-italic) weight/style, so nothing combo-side leaks in.
|
||||
QFont font(row.familyCombo->currentFont().family());
|
||||
font.setPointSize(row.sizeSpin->value());
|
||||
cfg.fonts[role] = font;
|
||||
|
||||
if (role == AppFont::CardText && row.minSpin != nullptr) {
|
||||
cfg.cardTextMinSize = row.minSpin->value();
|
||||
cfg.cardTextMaxSize = row.sizeSpin->value();
|
||||
}
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
||||
void FontGridWidget::retranslateUi()
|
||||
{
|
||||
QMetaEnum fontEnum = QMetaEnum::fromType<AppFont::Role>();
|
||||
for (int i = 0; i < fontEnum.keyCount(); ++i) {
|
||||
auto role = static_cast<AppFont::Role>(fontEnum.value(i));
|
||||
const FontRow &row = fontRows.value(role);
|
||||
|
||||
row.label->setText(roleDisplayName(role));
|
||||
row.label->setToolTip(tr(APP_FONT_DESCRIPTIONS.value(role, "")));
|
||||
row.familyCombo->setToolTip(tr(APP_FONT_DESCRIPTIONS.value(role, "")));
|
||||
row.familyCombo->setAccessibleName(roleDisplayName(role));
|
||||
if (role == AppFont::CardText && row.minSpin != nullptr) {
|
||||
row.minSpin->setToolTip(tr("Minimum card text size"));
|
||||
row.minSpin->setAccessibleName(tr("Minimum card text size"));
|
||||
row.minSpin->setSuffix(tr(" pt"));
|
||||
row.sizeSpin->setToolTip(tr("Maximum card text size"));
|
||||
row.sizeSpin->setAccessibleName(tr("Maximum card text size"));
|
||||
row.sizeSpin->setSuffix(tr(" pt"));
|
||||
continue;
|
||||
}
|
||||
row.sizeSpin->setToolTip(tr("Point size for %1").arg(roleDisplayName(role)));
|
||||
row.sizeSpin->setAccessibleName(tr("Point size for %1").arg(roleDisplayName(role)));
|
||||
row.sizeSpin->setSuffix(tr(" pt"));
|
||||
}
|
||||
}
|
||||
44
cockatrice/src/interface/palette_editor/font_grid_widget.h
Normal file
44
cockatrice/src/interface/palette_editor/font_grid_widget.h
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef COCKATRICE_FONT_GRID_WIDGET_H
|
||||
#define COCKATRICE_FONT_GRID_WIDGET_H
|
||||
|
||||
#include "../theme_config.h"
|
||||
|
||||
#include <QMap>
|
||||
#include <QWidget>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
class QFontComboBox;
|
||||
class QGridLayout;
|
||||
class QLabel;
|
||||
class QSpinBox;
|
||||
|
||||
// Per-role font editors — one (family, point size) row per AppFont::Role.
|
||||
// Owns the load/read round-trip for FontConfig but has no file I/O, mirroring
|
||||
// PaletteGridWidget. Only family and point size are edited; weight and italic
|
||||
// stay caller-side concerns and are stripped when reading back.
|
||||
class FontGridWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit FontGridWidget(QWidget *parent = nullptr);
|
||||
|
||||
void loadFonts(const FontConfig &cfg);
|
||||
FontConfig currentFontConfig() const;
|
||||
void retranslateUi();
|
||||
|
||||
signals:
|
||||
void fontsChanged();
|
||||
|
||||
private:
|
||||
struct FontRow
|
||||
{
|
||||
QLabel *label = nullptr;
|
||||
QFontComboBox *familyCombo = nullptr;
|
||||
QSpinBox *sizeSpin = nullptr;
|
||||
QSpinBox *minSpin = nullptr; // CardText only: shrink-to-fit floor
|
||||
};
|
||||
|
||||
QMap<AppFont::Role, FontRow> fontRows;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_FONT_GRID_WIDGET_H
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "../theme_config.h"
|
||||
#include "../theme_manager.h"
|
||||
#include "font_grid_widget.h"
|
||||
#include "palette_generator.h"
|
||||
#include "palette_grid_widget.h"
|
||||
#include "quick_setup_panel.h"
|
||||
|
|
@ -41,6 +42,7 @@ PaletteEditorDialog::PaletteEditorDialog(const QString &_themeDirPath, const QSt
|
|||
|
||||
// Load both scheme configs upfront so switching is instant
|
||||
loadSchemes();
|
||||
loadFonts();
|
||||
|
||||
loadedScheme = themeManager->isDarkMode(themeDirPath) ? "Dark" : "Light";
|
||||
|
||||
|
|
@ -125,6 +127,33 @@ void PaletteEditorDialog::setupUi()
|
|||
paletteGrid->setVisible(false);
|
||||
root->addWidget(paletteGrid, 1);
|
||||
|
||||
// Font section — sibling to the palette grid, sharing its collapsible
|
||||
// advanced area pattern. Fonts are shared per theme, not split by scheme.
|
||||
fontToggleButton = new QPushButton(this);
|
||||
fontToggleButton->setCheckable(true);
|
||||
fontToggleButton->setChecked(false);
|
||||
fontToggleButton->setFlat(true);
|
||||
fontToggleButton->setStyleSheet("QPushButton { text-align: left; padding: 5px 12px; font-weight: bold; }"
|
||||
"QPushButton:checked { }");
|
||||
root->addWidget(fontToggleButton);
|
||||
|
||||
fontSeparator = makeSeparator();
|
||||
fontSeparator->setVisible(false);
|
||||
root->addWidget(fontSeparator);
|
||||
|
||||
fontSection = new QWidget;
|
||||
auto *fontSectionLayout = new QVBoxLayout(fontSection);
|
||||
fontSectionLayout->setContentsMargins(0, 0, 0, 0);
|
||||
fontSectionLayout->setSpacing(0);
|
||||
fontNoteLabel = new QLabel(fontSection);
|
||||
fontNoteLabel->setContentsMargins(12, 4, 12, 0);
|
||||
fontNoteLabel->setWordWrap(true);
|
||||
fontSectionLayout->addWidget(fontNoteLabel);
|
||||
fontGrid = new FontGridWidget(fontSection);
|
||||
fontSectionLayout->addWidget(fontGrid);
|
||||
fontSection->setVisible(false);
|
||||
root->addWidget(fontSection);
|
||||
|
||||
// Footer
|
||||
root->addWidget(makeSeparator());
|
||||
footer = new QWidget;
|
||||
|
|
@ -157,6 +186,10 @@ void PaletteEditorDialog::setupUi()
|
|||
connect(autoApplyTimer, &QTimer::timeout, this, &PaletteEditorDialog::onApply);
|
||||
connect(quickSetupPanel, &QuickSetupPanel::valueChanged, this, &PaletteEditorDialog::onGenerateFromAccent);
|
||||
connect(paletteGrid, &PaletteGridWidget::paletteChanged, this, [this] { autoApplyTimer->start(); });
|
||||
connect(fontGrid, &FontGridWidget::fontsChanged, this, [this] {
|
||||
fontsDirty = true;
|
||||
autoApplyTimer->start();
|
||||
});
|
||||
connect(revertButton, &QPushButton::clicked, this, &PaletteEditorDialog::onRevertToDefault);
|
||||
connect(resetBtn, &QPushButton::clicked, this, &PaletteEditorDialog::onReset);
|
||||
connect(saveBtn, &QPushButton::clicked, this, &PaletteEditorDialog::onSave);
|
||||
|
|
@ -166,15 +199,32 @@ void PaletteEditorDialog::setupUi()
|
|||
paletteGridToggleButton->setText(open ? tr("▼ Edit Palette") : tr("▶ Edit Palette"));
|
||||
paletteGridSeparator->setVisible(open);
|
||||
paletteGrid->setVisible(open);
|
||||
|
||||
if (open) {
|
||||
setMinimumHeight(680);
|
||||
resize(width(), 680);
|
||||
} else {
|
||||
setMinimumHeight(220);
|
||||
adjustSize(); // shrinks to fit just the visible content
|
||||
}
|
||||
updateAdvancedHeight();
|
||||
});
|
||||
connect(fontToggleButton, &QPushButton::toggled, this, [this](bool open) {
|
||||
fontToggleButton->setText(open ? tr("▼ Edit Fonts") : tr("▶ Edit Fonts"));
|
||||
fontSeparator->setVisible(open);
|
||||
fontSection->setVisible(open);
|
||||
updateAdvancedHeight();
|
||||
});
|
||||
}
|
||||
|
||||
void PaletteEditorDialog::updateAdvancedHeight()
|
||||
{
|
||||
int height = 220;
|
||||
if (paletteGridToggleButton->isChecked()) {
|
||||
height += 460;
|
||||
}
|
||||
if (fontToggleButton->isChecked()) {
|
||||
height += 200;
|
||||
}
|
||||
setMinimumHeight(height);
|
||||
|
||||
if (paletteGrid->isVisible() || fontSection->isVisible()) {
|
||||
resize(width(), height);
|
||||
} else {
|
||||
adjustSize(); // shrinks to fit just the visible content
|
||||
}
|
||||
}
|
||||
|
||||
void PaletteEditorDialog::retranslateUi()
|
||||
|
|
@ -189,12 +239,16 @@ void PaletteEditorDialog::retranslateUi()
|
|||
editingLabel->setText(tr("Editing:"));
|
||||
paletteGridToggleButton->setText(tr("▶ Edit Palette"));
|
||||
paletteGridToggleButton->setToolTip(tr("Show or hide the per-role colour grid for manual tweaks"));
|
||||
fontToggleButton->setText(fontSection->isVisible() ? tr("▼ Edit Fonts") : tr("▶ Edit Fonts"));
|
||||
fontToggleButton->setToolTip(tr("Show or hide the per-purpose font settings for this theme"));
|
||||
fontNoteLabel->setText(tr("Fonts belong to theme %1 (shared by Light and Dark schemes)").arg(themeName));
|
||||
fontGrid->retranslateUi();
|
||||
revertButton->setText(tr("↺ Revert to theme default"));
|
||||
|
||||
resetBtn->setText(tr("Reset"));
|
||||
saveBtn->setText(tr("Save"));
|
||||
resetBtn->setToolTip(tr("Discard unsaved edits and restore the last saved palette"));
|
||||
saveBtn->setToolTip(tr("Write palette-%1.toml and reload the theme").arg(loadedScheme.toLower()));
|
||||
resetBtn->setToolTip(tr("Discard unsaved edits and restore the last saved palette and fonts"));
|
||||
saveBtn->setToolTip(tr("Write palette-%1.toml and fonts.toml, then reload the theme").arg(loadedScheme.toLower()));
|
||||
|
||||
if (saveDir.isEmpty() || !ThemeManager::isDirReallyWritable(saveDir)) {
|
||||
saveBtn->setEnabled(false);
|
||||
|
|
@ -228,6 +282,13 @@ void PaletteEditorDialog::loadSchemes()
|
|||
}
|
||||
}
|
||||
|
||||
void PaletteEditorDialog::loadFonts()
|
||||
{
|
||||
savedFontConfig = ThemeManager::loadDefaultFontConfig(themeDirPath, themeName);
|
||||
fontGrid->loadFonts(savedFontConfig);
|
||||
fontsDirty = false;
|
||||
}
|
||||
|
||||
void PaletteEditorDialog::seedAccentFromScheme(const QString &scheme)
|
||||
{
|
||||
QColor seed = workingConfig.value(scheme).colors.value(QPalette::Active).value(QPalette::Highlight);
|
||||
|
|
@ -258,6 +319,9 @@ void PaletteEditorDialog::onGenerateFromAccent(const QColor &accent, int intensi
|
|||
void PaletteEditorDialog::onApply()
|
||||
{
|
||||
themeManager->previewPalette(paletteGrid->currentPaletteConfig(), loadedScheme);
|
||||
if (fontsDirty) {
|
||||
themeManager->previewFonts(fontGrid->currentFontConfig());
|
||||
}
|
||||
}
|
||||
|
||||
void PaletteEditorDialog::onSave()
|
||||
|
|
@ -308,6 +372,20 @@ void PaletteEditorDialog::onSave()
|
|||
savedConfig[it.key()] = it.value();
|
||||
}
|
||||
|
||||
// Persist the shared per-theme fonts when they changed.
|
||||
if (fontsDirty) {
|
||||
const FontConfig fontCfg = fontGrid->currentFontConfig();
|
||||
if (fontCfg != savedFontConfig) {
|
||||
if (!ThemeManager::saveFontConfig(saveDir, fontCfg)) {
|
||||
QMessageBox::warning(this, tr("Save failed"),
|
||||
tr("Could not write %1 to:\n%2").arg(FontConfig::fileName(), saveDir));
|
||||
return;
|
||||
}
|
||||
savedFontConfig = fontCfg;
|
||||
}
|
||||
fontsDirty = false;
|
||||
}
|
||||
|
||||
themeManager->reloadCurrentTheme();
|
||||
accept();
|
||||
}
|
||||
|
|
@ -316,6 +394,12 @@ void PaletteEditorDialog::onReset()
|
|||
{
|
||||
workingConfig[loadedScheme] = savedConfig[loadedScheme];
|
||||
paletteGrid->loadPalette(savedConfig[loadedScheme]);
|
||||
// Restore the live theme before re-reading the grid: loadFonts resolves
|
||||
// unset roles, and the preview has currentFonts pointing at the edited
|
||||
// config until the theme is reloaded.
|
||||
themeManager->reloadCurrentTheme();
|
||||
fontGrid->loadFonts(savedFontConfig);
|
||||
fontsDirty = false;
|
||||
seedAccentFromScheme(loadedScheme);
|
||||
}
|
||||
|
||||
|
|
@ -350,6 +434,27 @@ void PaletteEditorDialog::onRevertToDefault()
|
|||
workingConfig[loadedScheme] = def;
|
||||
paletteGrid->loadPalette(def);
|
||||
seedAccentFromScheme(loadedScheme);
|
||||
|
||||
// Revert the shared per-theme fonts the same way: delete the user-written
|
||||
// fonts.toml so the theme falls back to its shipped default, then reflect
|
||||
// the resolved fonts in the editor.
|
||||
QFile::remove(QDir(saveDir).absoluteFilePath(FontConfig::fileName()));
|
||||
|
||||
// Reload the live theme so the font revert takes effect immediately.
|
||||
themeManager->reloadCurrentTheme();
|
||||
|
||||
const FontConfig fontDef = ThemeManager::loadDefaultFontConfig(themeDirPath, themeName);
|
||||
savedFontConfig = fontDef;
|
||||
fontGrid->loadFonts(fontDef);
|
||||
fontsDirty = false;
|
||||
}
|
||||
|
||||
void PaletteEditorDialog::reject()
|
||||
{
|
||||
// Discard any unsaved live preview (palette and fonts) so closing without
|
||||
// Save restores the active theme instead of leaking the preview globally.
|
||||
themeManager->reloadCurrentTheme();
|
||||
QDialog::reject();
|
||||
}
|
||||
|
||||
void PaletteEditorDialog::changeEvent(QEvent *e)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ class QComboBox;
|
|||
class QDialogButtonBox;
|
||||
class QPushButton;
|
||||
class PaletteGridWidget;
|
||||
class FontGridWidget;
|
||||
class QuickSetupPanel;
|
||||
class QFrame;
|
||||
class QWidget;
|
||||
|
|
@ -25,6 +26,7 @@ class PaletteEditorDialog : public QDialog
|
|||
public:
|
||||
explicit PaletteEditorDialog(const QString &themeDirPath, const QString &themeName, QWidget *parent = nullptr);
|
||||
void loadSchemes();
|
||||
void reject() override;
|
||||
|
||||
private slots:
|
||||
void onSave();
|
||||
|
|
@ -38,8 +40,10 @@ private:
|
|||
void setupUi();
|
||||
void retranslateUi();
|
||||
void refreshChromePalettes();
|
||||
void updateAdvancedHeight();
|
||||
void loadScheme(const QString &scheme); // snapshot current, switch, load
|
||||
void seedAccentFromScheme(const QString &scheme);
|
||||
void loadFonts(); // shared per theme, not split by light/dark
|
||||
|
||||
// Sub-widgets
|
||||
QWidget *header;
|
||||
|
|
@ -49,6 +53,11 @@ private:
|
|||
PaletteGridWidget *paletteGrid = nullptr;
|
||||
QPushButton *paletteGridToggleButton = nullptr;
|
||||
QFrame *paletteGridSeparator = nullptr;
|
||||
FontGridWidget *fontGrid = nullptr;
|
||||
QPushButton *fontToggleButton = nullptr;
|
||||
QFrame *fontSeparator = nullptr;
|
||||
QWidget *fontSection = nullptr;
|
||||
QLabel *fontNoteLabel = nullptr;
|
||||
QWidget *footer;
|
||||
QComboBox *schemeComboBox = nullptr;
|
||||
QDialogButtonBox *buttonBox = nullptr;
|
||||
|
|
@ -68,10 +77,18 @@ private:
|
|||
QMap<QString, PaletteConfig> workingConfig;
|
||||
QMap<QString, PaletteConfig> savedConfig;
|
||||
|
||||
// Fonts are shared per theme (fonts.toml, not split by light/dark), so a
|
||||
// single saved config suffices; the live edits are read from fontGrid.
|
||||
FontConfig savedFontConfig;
|
||||
// Set only by user-driven fontsChanged after the initial load completes.
|
||||
// Gates both previewFonts and the fonts.toml write so a palette-only Save
|
||||
// never materializes fallback fonts to disk.
|
||||
bool fontsDirty = false;
|
||||
|
||||
QTimer *autoApplyTimer = nullptr;
|
||||
|
||||
protected:
|
||||
void changeEvent(QEvent *e) override;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_PALETTE_EDITOR_DIALOG_H
|
||||
#endif // COCKATRICE_PALETTE_EDITOR_DIALOG_H
|
||||
|
|
|
|||
|
|
@ -76,6 +76,18 @@ PaletteGridWidget::PaletteGridWidget(QWidget *parent) : QWidget(parent)
|
|||
|
||||
layout = QtUtils::makeLayout<QVBoxLayout>(this);
|
||||
layout->addWidget(scroll);
|
||||
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, &PaletteGridWidget::applyInterfaceDefaultFont);
|
||||
}
|
||||
|
||||
void PaletteGridWidget::applyInterfaceDefaultFont()
|
||||
{
|
||||
// The editor's own chrome follows the InterfaceDefault theme role; bold stays caller-side.
|
||||
for (auto *label : headerLabels) {
|
||||
QFont headerFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
headerFont.setBold(true);
|
||||
label->setFont(headerFont);
|
||||
}
|
||||
}
|
||||
|
||||
void PaletteGridWidget::buildGrid(QWidget *host)
|
||||
|
|
@ -101,7 +113,8 @@ void PaletteGridWidget::buildGrid(QWidget *host)
|
|||
auto *label = new QLabel(groupHeaders[col], host);
|
||||
label->setAlignment(Qt::AlignCenter);
|
||||
label->setToolTip(groupTips[col]);
|
||||
label->setFont(QtUtils::boldFont(label->font()));
|
||||
// Family comes from the InterfaceDefault theme role; bold stays caller-side.
|
||||
label->setFont(QtUtils::boldFont(themeManager->appFont(AppFont::InterfaceDefault)));
|
||||
label->setAutoFillBackground(true);
|
||||
label->setContentsMargins(4, 4, 4, 4);
|
||||
grid->addWidget(label, 0, col + 1);
|
||||
|
|
@ -146,7 +159,7 @@ void PaletteGridWidget::buildGrid(QWidget *host)
|
|||
|
||||
auto *appHeader = new QLabel(tr("App colors"), host);
|
||||
appHeader->setToolTip(tr("Application-specific colors layered on top of the Qt palette"));
|
||||
appHeader->setFont(QtUtils::boldFont(appHeader->font()));
|
||||
appHeader->setFont(QtUtils::boldFont(themeManager->appFont(AppFont::InterfaceDefault)));
|
||||
appHeader->setAutoFillBackground(true);
|
||||
appHeader->setContentsMargins(4, 4, 4, 4);
|
||||
grid->addWidget(appHeader, appHeaderRow, 0, 1, 4);
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ private:
|
|||
void changeEvent(QEvent *e);
|
||||
void refreshChromePalettes();
|
||||
|
||||
private slots:
|
||||
void applyInterfaceDefaultFont();
|
||||
|
||||
private:
|
||||
QMap<QPalette::ColorGroup, QMap<QPalette::ColorRole, ColorButton *>> colorButtons;
|
||||
QMap<AppColor::Role, ColorButton *> appColorButtons;
|
||||
QScrollArea *scroll;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "quick_setup_panel.h"
|
||||
|
||||
#include "../theme_manager.h"
|
||||
#include "color_button.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
|
@ -28,10 +29,15 @@ QuickSetupPanel::QuickSetupPanel(QWidget *parent) : QWidget(parent)
|
|||
|
||||
labelLow = new QLabel(this);
|
||||
labelHigh = new QLabel(this);
|
||||
QFont small = labelLow->font();
|
||||
small.setPointSizeF(small.pointSizeF() * 0.82);
|
||||
labelLow->setFont(small);
|
||||
labelHigh->setFont(small);
|
||||
// Family comes from the InterfaceDefault theme role; the *0.82 size stays caller-side.
|
||||
auto applySmallFont = [this]() {
|
||||
QFont small = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
small.setPointSizeF(small.pointSizeF() * 0.82);
|
||||
labelLow->setFont(small);
|
||||
labelHigh->setFont(small);
|
||||
};
|
||||
applySmallFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, applySmallFont);
|
||||
QPalette dimmed = labelLow->palette();
|
||||
dimmed.setColor(QPalette::WindowText, qApp->palette().color(QPalette::Mid));
|
||||
labelLow->setPalette(dimmed);
|
||||
|
|
|
|||
|
|
@ -304,4 +304,183 @@ QPalette PaletteConfig::apply(QPalette base) const
|
|||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
bool FontConfig::hasFonts() const
|
||||
{
|
||||
return !fonts.isEmpty() || cardTextMinSize != 1 || cardTextMaxSize > 0;
|
||||
}
|
||||
|
||||
QString FontConfig::toToml() const
|
||||
{
|
||||
QMetaEnum roleEnum = QMetaEnum::fromType<AppFont::Role>();
|
||||
|
||||
QString entries;
|
||||
|
||||
for (auto it = fonts.cbegin(); it != fonts.cend(); ++it) {
|
||||
const char *roleName = roleEnum.valueToKey(it.key());
|
||||
|
||||
if (!roleName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QString family = it.value().family().trimmed();
|
||||
int pointSize = it.value().pointSize();
|
||||
|
||||
if (family.isEmpty() || pointSize <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
entries += QString("%1 = \"%2, %3\"\n").arg(QString(roleName), -20).arg(family).arg(pointSize);
|
||||
}
|
||||
|
||||
if (cardTextMinSize != 1) {
|
||||
entries += QString("%1 = %2\n").arg(QStringLiteral("CardTextMinSize"), -20).arg(cardTextMinSize);
|
||||
}
|
||||
|
||||
if (cardTextMaxSize > 0) {
|
||||
entries += QString("%1 = %2\n").arg(QStringLiteral("CardTextMaxSize"), -20).arg(cardTextMaxSize);
|
||||
}
|
||||
|
||||
if (entries.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return "[Fonts]\n" + entries + "\n";
|
||||
}
|
||||
|
||||
QString FontConfig::fileName()
|
||||
{
|
||||
return "fonts.toml";
|
||||
}
|
||||
|
||||
FontConfig FontConfig::fromFile(const QString &filePath)
|
||||
{
|
||||
FontConfig cfg;
|
||||
|
||||
QFile f(filePath);
|
||||
|
||||
if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
return cfg;
|
||||
}
|
||||
|
||||
QMetaEnum roleEnum = QMetaEnum::fromType<AppFont::Role>();
|
||||
|
||||
QString currentSection;
|
||||
|
||||
QTextStream in(&f);
|
||||
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine().trimmed();
|
||||
|
||||
if (line.isEmpty() || line.startsWith('#') || line.startsWith(';')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line.startsWith('[') && line.endsWith(']')) {
|
||||
currentSection = line.mid(1, line.length() - 2).trimmed();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentSection.compare("Fonts", Qt::CaseInsensitive) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int eq = line.indexOf('=');
|
||||
|
||||
if (eq < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QString key = line.left(eq).trimmed();
|
||||
QString value = line.mid(eq + 1).trimmed();
|
||||
|
||||
// Strip inline comments if preceded by whitespace
|
||||
for (int i = 1; i < value.size(); ++i) {
|
||||
if ((value[i] == '#' || value[i] == ';') && value[i - 1].isSpace()) {
|
||||
value = value.left(i).trimmed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Strip surrounding quotes, if any
|
||||
if (value.size() >= 2 &&
|
||||
((value.startsWith('"') && value.endsWith('"')) || (value.startsWith('\'') && value.endsWith('\'')))) {
|
||||
value = value.mid(1, value.size() - 2).trimmed();
|
||||
}
|
||||
|
||||
// CardText size bounds: bare integers, e.g. CardTextMinSize = 2.
|
||||
// Tolerate quoting like the family entries; skip invalid lines.
|
||||
QString sizeKey = key;
|
||||
if (sizeKey.startsWith("AppFont::")) {
|
||||
sizeKey = sizeKey.mid(QStringLiteral("AppFont::").size());
|
||||
}
|
||||
if (sizeKey.compare("CardTextMinSize", Qt::CaseInsensitive) == 0) {
|
||||
bool ok = false;
|
||||
int minSize = value.trimmed().toInt(&ok);
|
||||
if (!ok || minSize <= 0) {
|
||||
continue;
|
||||
}
|
||||
cfg.cardTextMinSize = minSize;
|
||||
continue;
|
||||
}
|
||||
if (sizeKey.compare("CardTextMaxSize", Qt::CaseInsensitive) == 0) {
|
||||
bool ok = false;
|
||||
int maxSize = value.trimmed().toInt(&ok);
|
||||
if (!ok || maxSize <= 0) {
|
||||
continue;
|
||||
}
|
||||
cfg.cardTextMaxSize = maxSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
int comma = value.lastIndexOf(',');
|
||||
|
||||
if (comma < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QString family = value.left(comma).trimmed();
|
||||
|
||||
// Tolerate a partially-quoted family, e.g. "Inter", 10
|
||||
if (family.size() >= 2 &&
|
||||
((family.startsWith('"') && family.endsWith('"')) || (family.startsWith('\'') && family.endsWith('\'')))) {
|
||||
family = family.mid(1, family.size() - 2).trimmed();
|
||||
}
|
||||
|
||||
bool ok = false;
|
||||
int pointSize = value.mid(comma + 1).trimmed().toInt(&ok);
|
||||
|
||||
if (!ok || family.isEmpty() || pointSize <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (key.startsWith("AppFont::")) {
|
||||
key = key.mid(QStringLiteral("AppFont::").size());
|
||||
}
|
||||
|
||||
int roleInt = roleEnum.keyToValue(key.toUtf8().constData());
|
||||
|
||||
if (roleInt < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Canonical family + point size only: a fresh QFont carries default
|
||||
// (non-bold, non-italic) weight/style, so nothing caller-side leaks in.
|
||||
// No validation against installed fonts; Qt substitution applies.
|
||||
QFont font(family);
|
||||
font.setPointSize(pointSize);
|
||||
cfg.fonts[static_cast<AppFont::Role>(roleInt)] = font;
|
||||
}
|
||||
|
||||
return cfg;
|
||||
}
|
||||
|
||||
FontConfig FontConfig::fromThemeDir(const QString &themeDirPath)
|
||||
{
|
||||
if (themeDirPath.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return fromFile(QDir(themeDirPath).absoluteFilePath(fileName()));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define COCKATRICE_THEME_CONFIG_H
|
||||
|
||||
#include <QColor>
|
||||
#include <QFont>
|
||||
#include <QMap>
|
||||
#include <QPalette>
|
||||
#include <QSharedPointer>
|
||||
|
|
@ -23,6 +24,23 @@ enum Role
|
|||
Q_ENUM_NS(Role)
|
||||
} // namespace AppColor
|
||||
|
||||
// Application-specific font roles, one configurable family + point size per
|
||||
// purpose. Stored in a shared fonts.toml under a [Fonts] section (one file per
|
||||
// theme, not split by light/dark). Only family and point size are stored;
|
||||
// weight/italic are stripped on load and stay caller-side concerns.
|
||||
namespace AppFont
|
||||
{
|
||||
Q_NAMESPACE
|
||||
enum Role
|
||||
{
|
||||
InterfaceDefault,
|
||||
ChatLog,
|
||||
CardText,
|
||||
DeckList,
|
||||
};
|
||||
Q_ENUM_NS(Role)
|
||||
} // namespace AppFont
|
||||
|
||||
struct ThemeConfig
|
||||
{
|
||||
QString colorScheme;
|
||||
|
|
@ -60,4 +78,41 @@ struct PaletteConfig
|
|||
QPalette apply(QPalette base) const;
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_THEME_CONFIG_H
|
||||
/** @brief Per-purpose font configuration, stored as family + point size only.
|
||||
*
|
||||
* Serialized to a shared fonts.toml file with a [Fonts] section, e.g.
|
||||
* @code
|
||||
* [Fonts]
|
||||
* InterfaceDefault = "Inter, 10"
|
||||
* CardText = "Noto Serif, 12"
|
||||
* CardTextMinSize = 1
|
||||
* @endcode
|
||||
* CardText stores family + MAX size; cardTextMinSize stores the overlay
|
||||
* shrink-to-fit floor (omitted from TOML when 1).
|
||||
*/
|
||||
struct FontConfig
|
||||
{
|
||||
QMap<AppFont::Role, QFont> fonts;
|
||||
int cardTextMinSize = 1;
|
||||
/// Optional size-only maximum for CardText, used by the retired maxFontSize
|
||||
/// migration so seeding it does not have to pin a family.
|
||||
int cardTextMaxSize = 0;
|
||||
|
||||
bool operator==(const FontConfig &rhs) const
|
||||
{
|
||||
return fonts == rhs.fonts && cardTextMinSize == rhs.cardTextMinSize && cardTextMaxSize == rhs.cardTextMaxSize;
|
||||
}
|
||||
bool operator!=(const FontConfig &rhs) const
|
||||
{
|
||||
return !(*this == rhs);
|
||||
}
|
||||
bool hasFonts() const;
|
||||
QString toToml() const;
|
||||
|
||||
static QString fileName();
|
||||
|
||||
static FontConfig fromFile(const QString &filePath);
|
||||
static FontConfig fromThemeDir(const QString &themeDirPath);
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_THEME_CONFIG_H
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QFlags>
|
||||
#include <QFontDatabase>
|
||||
#include <QGuiApplication>
|
||||
#include <QIODevice>
|
||||
#include <QLatin1Char>
|
||||
|
|
@ -127,8 +128,10 @@ static QString usableDefaultStyle(const QString &style)
|
|||
ThemeManager::ThemeManager(QObject *parent) : QObject(parent)
|
||||
{
|
||||
defaultStyleName = usableDefaultStyle(qApp->style()->objectName());
|
||||
// Capture the untouched application palette before any theme is applied.
|
||||
// Capture the untouched application palette and font before any theme is
|
||||
// applied.
|
||||
defaultPalette = qApp->palette();
|
||||
defaultFont = qApp->font();
|
||||
ensureThemeDirectoryExists();
|
||||
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
|
||||
connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, [this] {
|
||||
|
|
@ -440,6 +443,46 @@ PaletteConfig ThemeManager::loadDefaultPaletteConfig(const QString &themeDirPath
|
|||
return cfg;
|
||||
}
|
||||
|
||||
FontConfig ThemeManager::loadFontConfig(const QString &themeDirPath)
|
||||
{
|
||||
if (themeDirPath.isEmpty()) {
|
||||
return {};
|
||||
}
|
||||
return FontConfig::fromThemeDir(themeDirPath);
|
||||
}
|
||||
|
||||
FontConfig ThemeManager::loadDefaultFontConfig(const QString &themeDirPath, const QString &themeName)
|
||||
{
|
||||
FontConfig cfg = FontConfig::fromThemeDir(themeDirPath);
|
||||
if (!cfg.hasFonts()) {
|
||||
// The shipped fonts.toml may live in the system theme directory rather
|
||||
// than the resolved (user) theme directory, so built-in themes still
|
||||
// get their curated fonts.
|
||||
cfg = FontConfig::fromThemeDir(QDir(systemThemesBasePath()).absoluteFilePath(themeName));
|
||||
}
|
||||
return cfg;
|
||||
}
|
||||
|
||||
bool ThemeManager::saveFontConfig(const QString &themeDirPath, const FontConfig &cfg)
|
||||
{
|
||||
if (themeDirPath.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QDir dir(themeDirPath);
|
||||
if (!dir.exists()) {
|
||||
dir.mkpath(".");
|
||||
}
|
||||
|
||||
QFile f(dir.absoluteFilePath(FontConfig::fileName()));
|
||||
if (!f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QTextStream(&f) << cfg.toToml();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ThemeManager::commitPalette(const QString &themeDirPath, const QString &colorScheme, const PaletteConfig &cfg)
|
||||
{
|
||||
if (!savePaletteConfig(themeDirPath, colorScheme, cfg)) {
|
||||
|
|
@ -488,6 +531,24 @@ void ThemeManager::previewPalette(const PaletteConfig &cfg, const QString &schem
|
|||
applyStyleAndPalette(themeName, themeCfg, cfg, scheme);
|
||||
}
|
||||
|
||||
void ThemeManager::previewFonts(const FontConfig &cfg)
|
||||
{
|
||||
currentFonts = cfg;
|
||||
|
||||
// QApplication::setFont already sends a font change to every widget, so a
|
||||
// repolish pass is not needed for fonts (unlike the palette path).
|
||||
const auto it = cfg.fonts.constFind(AppFont::InterfaceDefault);
|
||||
if (it != cfg.fonts.constEnd()) {
|
||||
qApp->setFont(it.value());
|
||||
} else {
|
||||
// A config without InterfaceDefault means "no override": restore the
|
||||
// startup font instead of leaving the last preview applied.
|
||||
qApp->setFont(defaultFont);
|
||||
}
|
||||
|
||||
emit fontsChanged();
|
||||
}
|
||||
|
||||
void ThemeManager::applyStyleAndPalette(const QString &themeName,
|
||||
const ThemeConfig &themeCfg,
|
||||
const PaletteConfig &palCfg,
|
||||
|
|
@ -591,6 +652,80 @@ QColor ThemeManager::appColor(AppColor::Role role) const
|
|||
return accent;
|
||||
}
|
||||
|
||||
QFont ThemeManager::appFont(AppFont::Role role) const
|
||||
{
|
||||
const auto it = currentFonts.fonts.constFind(role);
|
||||
if (it != currentFonts.fonts.constEnd()) {
|
||||
return it.value();
|
||||
}
|
||||
|
||||
// Role fallbacks preserve the pre-theme defaults when no fonts.toml is
|
||||
// present: an unset role resolves to the application font. Surfaces that
|
||||
// hardcoded a different family ask for it explicitly: counter painters
|
||||
// through cardTextFont(), the deck view headers and printed deck list
|
||||
// through deckListFont(), the report dialogs through
|
||||
// report_utils::reportLogFont(). Only the family basis is fixed there;
|
||||
// sizes stay caller-side.
|
||||
return qApp->font();
|
||||
}
|
||||
|
||||
bool ThemeManager::hasAppFont(AppFont::Role role) const
|
||||
{
|
||||
return currentFonts.fonts.contains(role);
|
||||
}
|
||||
|
||||
QFont ThemeManager::cardTextFont() const
|
||||
{
|
||||
if (hasAppFont(AppFont::CardText)) {
|
||||
return appFont(AppFont::CardText);
|
||||
}
|
||||
QFont serifFont(QStringLiteral("Serif"));
|
||||
serifFont.setStyleHint(QFont::Serif);
|
||||
serifFont.setPointSize(12);
|
||||
return serifFont;
|
||||
}
|
||||
|
||||
QFont ThemeManager::deckListFont() const
|
||||
{
|
||||
if (hasAppFont(AppFont::DeckList)) {
|
||||
return appFont(AppFont::DeckList);
|
||||
}
|
||||
QFont serifFont(QStringLiteral("Serif"));
|
||||
serifFont.setStyleHint(QFont::Serif);
|
||||
return serifFont;
|
||||
}
|
||||
|
||||
QFont ThemeManager::defaultAppFont(AppFont::Role /*role*/) const
|
||||
{
|
||||
// No per-role scaling and no preview: an unset role resolves to the font
|
||||
// captured at startup, which is what the theme falls back to once the
|
||||
// editor closes.
|
||||
return defaultFont;
|
||||
}
|
||||
|
||||
int ThemeManager::cardTextMaxSize() const
|
||||
{
|
||||
if (currentFonts.cardTextMaxSize > 0) {
|
||||
return currentFonts.cardTextMaxSize;
|
||||
}
|
||||
const auto it = currentFonts.fonts.constFind(AppFont::CardText);
|
||||
if (it != currentFonts.fonts.constEnd()) {
|
||||
const int size = it.value().pointSize();
|
||||
if (size > 0) {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
return 12;
|
||||
}
|
||||
|
||||
int ThemeManager::cardTextMinSize() const
|
||||
{
|
||||
if (currentFonts.cardTextMinSize > 0) {
|
||||
return currentFonts.cardTextMinSize;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ThemeManager::themeChangedSlot()
|
||||
{
|
||||
QString themeName = SettingsCache::instance().getThemeName();
|
||||
|
|
@ -642,6 +777,19 @@ void ThemeManager::themeChangedSlot()
|
|||
|
||||
applyStyleAndPalette(themeName, themeCfg, palette, activeScheme);
|
||||
|
||||
// ── Load fonts: shared per theme, no light/dark split ───────────────────
|
||||
FontConfig fonts = loadDefaultFontConfig(dirPath, themeName);
|
||||
currentFonts = fonts;
|
||||
const auto fontIt = currentFonts.fonts.constFind(AppFont::InterfaceDefault);
|
||||
if (fontIt != currentFonts.fonts.constEnd()) {
|
||||
qApp->setFont(fontIt.value());
|
||||
} else {
|
||||
// No theme font: restore the pristine application font captured at
|
||||
// startup, so a reverted preview cannot leak into the live theme.
|
||||
qApp->setFont(defaultFont);
|
||||
}
|
||||
emit fontsChanged();
|
||||
|
||||
QStringList resources;
|
||||
if (!dirPath.isEmpty()) {
|
||||
resources << dir.absolutePath();
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
#include <QFont>
|
||||
#include <QLoggingCategory>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
|
|
@ -47,10 +48,15 @@ private:
|
|||
// palette is applied. Used as the base when a theme supplies no palette, so
|
||||
// switching away from a custom palette restores the original colours.
|
||||
QPalette defaultPalette;
|
||||
// Pristine application font captured at startup, before any theme font is
|
||||
// applied. Restored when a theme (or a preview) supplies no InterfaceDefault
|
||||
// font, so switching away from a themed font cannot leave it behind.
|
||||
QFont defaultFont;
|
||||
QString currentThemePath;
|
||||
std::array<QBrush, Role::MaxRole + 1> brushes;
|
||||
QStringMap availableThemes;
|
||||
QMap<AppColor::Role, QColor> currentAppColors;
|
||||
FontConfig currentFonts;
|
||||
/*
|
||||
Internal cache for multiple backgrounds
|
||||
*/
|
||||
|
|
@ -105,6 +111,9 @@ public:
|
|||
// Load/save per-scheme palette colors
|
||||
static PaletteConfig loadPaletteConfig(const QString &themeDirPath, const QString &colorScheme);
|
||||
static bool savePaletteConfig(const QString &themeDirPath, const QString &colorScheme, const PaletteConfig &cfg);
|
||||
// Load/save shared per-theme fonts (fonts.toml, not split by scheme)
|
||||
static FontConfig loadFontConfig(const QString &themeDirPath);
|
||||
static bool saveFontConfig(const QString &themeDirPath, const FontConfig &cfg);
|
||||
// Resolve prefix to a scheme-qualified "theme:" path. Existence is probed
|
||||
// internally across the formats themes may ship (.png/.jpg/.svg), so
|
||||
// callers load the returned path directly. Prefers "<prefix>-<dark|light>"
|
||||
|
|
@ -123,6 +132,9 @@ public:
|
|||
// theme directory when it is absent from the resolved (user) directory.
|
||||
static PaletteConfig
|
||||
loadDefaultPaletteConfig(const QString &themeDirPath, const QString &themeName, const QString &colorScheme);
|
||||
// Load the theme's shipped default fonts, falling back to the system theme
|
||||
// directory when fonts.toml is absent from the resolved (user) directory.
|
||||
static FontConfig loadDefaultFontConfig(const QString &themeDirPath, const QString &themeName);
|
||||
/** @brief Writes cfg to disk as the theme's palette-<scheme>.toml and updates the
|
||||
* theme's stored colour scheme to match. Shared by PaletteEditorDialog::onSave
|
||||
* and FirstRunWizard's theme step so the two "generate + keep" paths can't drift. */
|
||||
|
|
@ -132,10 +144,36 @@ public:
|
|||
|
||||
void reloadCurrentTheme();
|
||||
void previewPalette(const PaletteConfig &cfg, const QString &scheme);
|
||||
void previewFonts(const FontConfig &cfg);
|
||||
|
||||
// Resolves an application color role: the theme's stored [AppColors] value
|
||||
// when present, otherwise a palette-accent-derived fallback.
|
||||
QColor appColor(AppColor::Role role) const;
|
||||
/** @brief Resolves an application font role: the theme's stored [Fonts]
|
||||
* value when present, otherwise the application font. Roles that
|
||||
* had a historical hardcoded family ask for it through
|
||||
* cardTextFont() and deckListFont() instead. */
|
||||
QFont appFont(AppFont::Role role) const;
|
||||
/** @brief Whether the active theme defines this role in fonts.toml. */
|
||||
bool hasAppFont(AppFont::Role role) const;
|
||||
/** @brief The CardText role with its historical Serif fallback. Used by the
|
||||
* counter painters, which were Serif before the role existed. */
|
||||
QFont cardTextFont() const;
|
||||
/** @brief The DeckList role with its historical Serif fallback. Used by the
|
||||
* two surfaces that hardcoded Serif before the role existed (the
|
||||
* deck view zone headers and the printed deck list); every other
|
||||
* DeckList reader falls back to the application font. */
|
||||
QFont deckListFont() const;
|
||||
/** @brief Resolves an application font role against the startup font only,
|
||||
* ignoring any previewed config in currentFonts. Editors that show
|
||||
* "what this role resolves to" must use this, because appFont()
|
||||
* reflects a live preview while the editor is open. */
|
||||
QFont defaultAppFont(AppFont::Role role) const;
|
||||
/** @brief CardText max size: stored CardTextMaxSize, else the CardText
|
||||
* point size, else 12. */
|
||||
int cardTextMaxSize() const;
|
||||
/** @brief CardText shrink-to-fit floor: stored CardTextMinSize, else 1. */
|
||||
int cardTextMinSize() const;
|
||||
|
||||
QBrush &getBgBrush(Role zone);
|
||||
QBrush getExtraBgBrush(Role zone, int zoneId = 0);
|
||||
|
|
@ -144,6 +182,7 @@ protected slots:
|
|||
signals:
|
||||
void themeChanged();
|
||||
void paletteChanged();
|
||||
void fontsChanged();
|
||||
};
|
||||
|
||||
extern ThemeManager *themeManager;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "art_crop_attribution.h"
|
||||
|
||||
#include "../../theme_manager.h"
|
||||
#include "libcockatrice/card/printing/printing_info.h"
|
||||
|
||||
#include <QColor>
|
||||
|
|
@ -35,7 +36,10 @@ QRectF paintArtAttribution(QPainter &painter,
|
|||
|
||||
painter.save();
|
||||
|
||||
// Family comes from the CardText theme role; the incoming painter size
|
||||
// stays the basis for the scale factor exactly as before.
|
||||
QFont font = painter.font();
|
||||
font.setFamily(themeManager->appFont(AppFont::CardText).family());
|
||||
font.setPointSizeF(qMax(6.0, font.pointSizeF() * scale));
|
||||
painter.setFont(font);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "card_info_picture_with_text_overlay_widget.h"
|
||||
|
||||
#include "../../theme_manager.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QChar>
|
||||
#include <QFont>
|
||||
|
|
@ -43,6 +45,7 @@ CardInfoPictureWithTextOverlayWidget::CardInfoPictureWithTextOverlayWidget(QWidg
|
|||
fontSize(fontSize), textAlignment(alignment), highlighted(false)
|
||||
{
|
||||
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, &CardInfoPictureWithTextOverlayWidget::applyCardTextFont);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -84,6 +87,7 @@ void CardInfoPictureWithTextOverlayWidget::setOutlineColor(const QColor &color)
|
|||
void CardInfoPictureWithTextOverlayWidget::setFontSize(const int size)
|
||||
{
|
||||
fontSize = size > 0 ? size : 1;
|
||||
hasExplicitFontSize = true;
|
||||
update();
|
||||
}
|
||||
|
||||
|
|
@ -97,6 +101,13 @@ void CardInfoPictureWithTextOverlayWidget::setTextAlignment(const Qt::Alignment
|
|||
update();
|
||||
}
|
||||
|
||||
void CardInfoPictureWithTextOverlayWidget::applyCardTextFont()
|
||||
{
|
||||
// The overlay paint reads the CardText role font at paint time, so a
|
||||
// theme font change only needs a repaint here.
|
||||
update();
|
||||
}
|
||||
|
||||
void CardInfoPictureWithTextOverlayWidget::setHighlighted(bool _highlighted)
|
||||
{
|
||||
if (highlighted == _highlighted) {
|
||||
|
|
@ -168,9 +179,13 @@ void CardInfoPictureWithTextOverlayWidget::paintEvent(QPaintEvent *event)
|
|||
return;
|
||||
}
|
||||
|
||||
// Calculate the optimal font size
|
||||
QFont font = painter.font();
|
||||
int optimalFontSize = fontSize; // Start with the user-defined font size
|
||||
// Calculate the optimal font size. The family comes from the CardText
|
||||
// theme role; the start size is the explicit size when set (e.g. deck
|
||||
// preview 24), else the theme max, shrinking down to the theme min floor.
|
||||
QFont font = themeManager->appFont(AppFont::CardText);
|
||||
const int themeMin = std::max(1, themeManager->cardTextMinSize());
|
||||
const int themeMax = std::max(themeMin, std::max(1, themeManager->cardTextMaxSize()));
|
||||
int optimalFontSize = hasExplicitFontSize ? std::max(1, fontSize) : themeMax;
|
||||
const QFontMetrics baseMetrics(font);
|
||||
int textWidth = pixmapRect.width();
|
||||
|
||||
|
|
@ -188,7 +203,7 @@ void CardInfoPictureWithTextOverlayWidget::paintEvent(QPaintEvent *event)
|
|||
}
|
||||
|
||||
--optimalFontSize;
|
||||
} while (optimalFontSize > 1);
|
||||
} while (optimalFontSize > themeMin);
|
||||
|
||||
// Apply the calculated font size
|
||||
painter.setFont(font);
|
||||
|
|
@ -215,7 +230,7 @@ void CardInfoPictureWithTextOverlayWidget::paintEvent(QPaintEvent *event)
|
|||
int totalTextHeight = wrappedText.count('\n') * fontMetrics.height() + fontMetrics.height();
|
||||
|
||||
// Adjust font size if the total text height exceeds the pixmap height
|
||||
while (totalTextHeight > pixmapRect.height() && optimalFontSize > 1) {
|
||||
while (totalTextHeight > pixmapRect.height() && optimalFontSize > themeMin) {
|
||||
--optimalFontSize;
|
||||
font.setPointSize(optimalFontSize);
|
||||
painter.setFont(font);
|
||||
|
|
@ -284,8 +299,10 @@ QSize CardInfoPictureWithTextOverlayWidget::minimumSizeHint() const
|
|||
const QSize pixmapSize = pixmap.isNull() ? QSize(0, 0) : pixmap.size();
|
||||
|
||||
// Get the font metrics for the overlay text
|
||||
QFont font;
|
||||
font.setPointSize(fontSize);
|
||||
QFont font = themeManager->appFont(AppFont::CardText);
|
||||
const int themeMin = std::max(1, themeManager->cardTextMinSize());
|
||||
const int themeMax = std::max(themeMin, std::max(1, themeManager->cardTextMaxSize()));
|
||||
font.setPointSize(hasExplicitFontSize ? std::max(1, fontSize) : themeMax);
|
||||
const QFontMetrics fontMetrics(font);
|
||||
|
||||
// Calculate the height required for the text
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ protected:
|
|||
void mousePressEvent(QMouseEvent *event) override;
|
||||
[[nodiscard]] QSize minimumSizeHint() const override;
|
||||
|
||||
private slots:
|
||||
void applyCardTextFont();
|
||||
|
||||
private:
|
||||
void drawOutlinedText(QPainter &painter,
|
||||
const QRect &textRect,
|
||||
|
|
@ -57,6 +60,7 @@ private:
|
|||
QColor textColor;
|
||||
QColor outlineColor;
|
||||
int fontSize;
|
||||
bool hasExplicitFontSize = false;
|
||||
Qt::Alignment textAlignment;
|
||||
bool highlighted;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "resizable_panel.h"
|
||||
|
||||
#include "../interface/theme_manager.h"
|
||||
#include "abstract_analytics_panel_widget.h"
|
||||
#include "libcockatrice/utility/qt_utils.h"
|
||||
|
||||
|
|
@ -12,6 +13,7 @@
|
|||
#include <QDropEvent>
|
||||
#include <QEvent>
|
||||
#include <QFlags>
|
||||
#include <QFont>
|
||||
#include <QFrame>
|
||||
#include <QHBoxLayout>
|
||||
#include <QMimeData>
|
||||
|
|
@ -93,9 +95,17 @@ ResizablePanel::ResizablePanel(const QString &_typeId, AbstractAnalyticsPanelWid
|
|||
|
||||
dragButton->setStyleSheet(QString("QPushButton { "
|
||||
"background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 %1, stop:1 %2); "
|
||||
"border: none; color: %3; font-size: 10px; }"
|
||||
"border: none; color: %3; }"
|
||||
"QPushButton:hover { background: %4; }")
|
||||
.arg(mid.name(), dark.name(), placeholderText.name(), midLight.name()));
|
||||
// Family comes from the InterfaceDefault theme role; the 10px size stays caller-side.
|
||||
auto applyDragFont = [this]() {
|
||||
QFont dragFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
dragFont.setPixelSize(10);
|
||||
dragButton->setFont(dragFont);
|
||||
};
|
||||
applyDragFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, applyDragFont);
|
||||
|
||||
resizeHandle->setStyleSheet(QString("QWidget { background: qlineargradient(x1:0, y1:0, x2:0, y2:1, "
|
||||
"stop:0 %1, stop:1 %2); }")
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "deck_list_style_proxy.h"
|
||||
|
||||
#include "../../theme_manager.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
#include <QFont>
|
||||
|
|
@ -8,6 +10,16 @@
|
|||
#include <libcockatrice/models/deck_list/deck_list_model.h>
|
||||
#include <qnamespace.h>
|
||||
|
||||
DeckListStyleProxy::DeckListStyleProxy(QObject *parent) : QIdentityProxyModel(parent)
|
||||
{
|
||||
// FontRole data reads the DeckList role live; rebroadcast so attached
|
||||
// views re-query instead of waiting for an incidental repaint.
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, [this] {
|
||||
emit layoutAboutToBeChanged();
|
||||
emit layoutChanged();
|
||||
});
|
||||
}
|
||||
|
||||
QVariant DeckListStyleProxy::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
QModelIndex src = mapToSource(index);
|
||||
|
|
@ -20,7 +32,8 @@ QVariant DeckListStyleProxy::data(const QModelIndex &index, int role) const
|
|||
bool isCard = src.data(DeckRoles::IsCardRole).toBool();
|
||||
|
||||
if (role == Qt::FontRole && !isCard) {
|
||||
QFont f;
|
||||
// Family comes from the DeckList theme role; bold stays caller-side.
|
||||
QFont f = themeManager->appFont(AppFont::DeckList);
|
||||
f.setBold(true);
|
||||
return f;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ class DeckListStyleProxy : public QIdentityProxyModel
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
using QIdentityProxyModel::QIdentityProxyModel;
|
||||
explicit DeckListStyleProxy(QObject *parent = nullptr);
|
||||
|
||||
[[nodiscard]] QVariant data(const QModelIndex &index, int role) const override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
#include "dlg_my_reports.h"
|
||||
|
||||
#include "../interface/theme_manager.h"
|
||||
#include "../utility/report_utils.h"
|
||||
#include "abstract_client.h"
|
||||
#include "libcockatrice/protocol/pb/response.pb.h"
|
||||
#include "libcockatrice/protocol/pb/serverinfo_report.pb.h"
|
||||
|
||||
#include <QAbstractItemView>
|
||||
#include <QFont>
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QHeaderView>
|
||||
|
|
@ -24,7 +26,6 @@
|
|||
#include <libcockatrice/protocol/pb/response_report_details.pb.h>
|
||||
#include <libcockatrice/protocol/pb/response_report_my_list.pb.h>
|
||||
#include <libcockatrice/protocol/pending_command.h>
|
||||
#include <libcockatrice/utility/qt_utils.h>
|
||||
#include <qnamespace.h>
|
||||
#include <string>
|
||||
|
||||
|
|
@ -69,7 +70,8 @@ DlgMyReports::DlgMyReports(AbstractClient *_client, QWidget *parent)
|
|||
auto *chatGroup = new QGroupBox(tr("Chat Log Context"));
|
||||
chatLogEdit = new QTextEdit;
|
||||
chatLogEdit->setReadOnly(true);
|
||||
chatLogEdit->setFont(QtUtils::monospaceFont());
|
||||
applyChatLogFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, &DlgMyReports::applyChatLogFont);
|
||||
auto *chatLayout = new QVBoxLayout(chatGroup);
|
||||
chatLayout->setContentsMargins(4, 4, 4, 4);
|
||||
chatLayout->addWidget(chatLogEdit);
|
||||
|
|
@ -122,6 +124,11 @@ DlgMyReports::DlgMyReports(AbstractClient *_client, QWidget *parent)
|
|||
refreshList();
|
||||
}
|
||||
|
||||
void DlgMyReports::applyChatLogFont()
|
||||
{
|
||||
chatLogEdit->setFont(report_utils::reportLogFont());
|
||||
}
|
||||
|
||||
void DlgMyReports::refreshList()
|
||||
{
|
||||
selectedReportIdBeforeRefresh = selectedReportId;
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ private slots:
|
|||
void reportDetailsResponse(const Response &response);
|
||||
void addComment();
|
||||
void addCommentResponse(const Response &response);
|
||||
void applyChatLogFont();
|
||||
|
||||
private:
|
||||
void loadReportDetails(const ServerInfo_Report &report);
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
#include "dlg_report_user.h"
|
||||
|
||||
#include "../interface/theme_manager.h"
|
||||
#include "../utility/report_utils.h"
|
||||
#include "abstract_client.h"
|
||||
#include "libcockatrice/protocol/pb/response.pb.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QFont>
|
||||
#include <QGridLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QLabel>
|
||||
|
|
@ -91,7 +94,8 @@ DlgReportUser::DlgReportUser(AbstractClient *_client,
|
|||
auto *chatLayout = new QVBoxLayout(chatGroup);
|
||||
chatLogEdit = new QTextEdit;
|
||||
chatLogEdit->setReadOnly(true);
|
||||
chatLogEdit->setFont(QtUtils::monospaceFont());
|
||||
applyChatLogFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, &DlgReportUser::applyChatLogFont);
|
||||
if (!_autoChatLog.isEmpty()) {
|
||||
chatLogEdit->setPlainText(_autoChatLog);
|
||||
} else {
|
||||
|
|
@ -120,6 +124,11 @@ DlgReportUser::DlgReportUser(AbstractClient *_client,
|
|||
layout->addWidget(buttonBox);
|
||||
}
|
||||
|
||||
void DlgReportUser::applyChatLogFont()
|
||||
{
|
||||
chatLogEdit->setFont(report_utils::reportLogFont());
|
||||
}
|
||||
|
||||
void DlgReportUser::actSubmit()
|
||||
{
|
||||
const QString description = descriptionEdit->toPlainText().trimmed();
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ public:
|
|||
private slots:
|
||||
void actSubmit();
|
||||
void reportResponse(const Response &response);
|
||||
void applyChatLogFont();
|
||||
|
||||
private:
|
||||
static QString categoryLabel(const QString &key);
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "../deck_share/shared_deck_preview_widget.h"
|
||||
#include "../general/layout_containers/flow_widget.h"
|
||||
#include "../interface/theme_manager.h"
|
||||
|
||||
#include <QAbstractButton>
|
||||
#include <QDateTime>
|
||||
|
|
@ -35,9 +36,14 @@ DlgSharedDecksPreview::DlgSharedDecksPreview(QWidget *parent,
|
|||
// QLabels render AutoText and markup would otherwise be shown as rich text.
|
||||
auto *titleLabel =
|
||||
new QLabel(tr("Share: %1").arg((shareName.isEmpty() ? tr("Untitled") : shareName).toHtmlEscaped()), this);
|
||||
QFont titleFont = QtUtils::boldFont(titleLabel->font());
|
||||
titleFont.setPointSize(titleFont.pointSize() + 2);
|
||||
titleLabel->setFont(titleFont);
|
||||
// Family comes from the InterfaceDefault theme role; the +2 size and bold stay caller-side.
|
||||
auto applyTitleFont = [titleLabel]() {
|
||||
QFont titleFont = QtUtils::boldFont(themeManager->appFont(AppFont::InterfaceDefault));
|
||||
titleFont.setPointSize(titleFont.pointSize() + 2);
|
||||
titleLabel->setFont(titleFont);
|
||||
};
|
||||
applyTitleFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, applyTitleFont);
|
||||
mainLayout->addWidget(titleLabel);
|
||||
|
||||
if (!serverText.isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
#include "../../../client/settings/cache_settings.h"
|
||||
#include "../../pixel_map_generator.h"
|
||||
#include "../interface/theme_manager.h"
|
||||
#include "../settings_page/abstract_settings_page.h"
|
||||
#include "../settings_page/appearance_settings_page.h"
|
||||
#include "../settings_page/deck_editor_settings_page.h"
|
||||
|
|
@ -199,6 +200,10 @@ void SettingsView::setupUi()
|
|||
searchDelegate->setPageIcons(icons);
|
||||
searchResultsView->viewport()->update();
|
||||
});
|
||||
// The search delegate reads the InterfaceDefault role at paint time, so a
|
||||
// font change only needs a repaint, mirroring the theme change above.
|
||||
connect(themeManager, &ThemeManager::fontsChanged, searchResultsView,
|
||||
[this] { searchResultsView->viewport()->update(); });
|
||||
|
||||
// Build search index after pages are created
|
||||
buildSearchIndex();
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
#include "banner_widget.h"
|
||||
|
||||
#include "../../../pixel_map_generator.h"
|
||||
#include "../../../theme_manager.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
#include <QFont>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLinearGradient>
|
||||
#include <QPainter>
|
||||
|
|
@ -28,7 +30,9 @@ BannerWidget::BannerWidget(QWidget *parent, const QString &text, Qt::Orientation
|
|||
if (transparency > 50) {
|
||||
textColor = " color: white;";
|
||||
}
|
||||
bannerLabel->setStyleSheet("font-size: 24px; font-weight: bold;" + textColor);
|
||||
bannerLabel->setStyleSheet(textColor);
|
||||
applyInterfaceDefaultFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, &BannerWidget::applyInterfaceDefaultFont);
|
||||
|
||||
layout->addWidget(iconLabel);
|
||||
layout->addWidget(bannerLabel);
|
||||
|
|
@ -56,6 +60,16 @@ void BannerWidget::setText(const QString &text) const
|
|||
bannerLabel->setText(text);
|
||||
}
|
||||
|
||||
void BannerWidget::applyInterfaceDefaultFont()
|
||||
{
|
||||
// Family comes from the InterfaceDefault theme role; the 24px size and
|
||||
// bold weight previously carried by the stylesheet stay caller-side.
|
||||
QFont bannerFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
bannerFont.setPixelSize(24);
|
||||
bannerFont.setWeight(QFont::Bold);
|
||||
bannerLabel->setFont(bannerFont);
|
||||
}
|
||||
|
||||
void BannerWidget::setClickable(bool _clickable)
|
||||
{
|
||||
clickable = _clickable;
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ signals:
|
|||
private slots:
|
||||
void toggleBuddyVisibility() const;
|
||||
void updateDropdownIconState() const;
|
||||
void applyInterfaceDefaultFont();
|
||||
};
|
||||
|
||||
#endif // BANNER_WIDGET_H
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "bar_chart_widget.h"
|
||||
|
||||
#include "../../interface/theme_manager.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QFlags>
|
||||
#include <QFont>
|
||||
|
|
@ -19,6 +21,10 @@
|
|||
BarChartWidget::BarChartWidget(QWidget *parent) : QWidget(parent)
|
||||
{
|
||||
setMouseTracking(true);
|
||||
|
||||
// Labels read the InterfaceDefault role at paint time, so a font change
|
||||
// only needs a repaint.
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, [this] { update(); });
|
||||
}
|
||||
|
||||
void BarChartWidget::setBars(const QVector<BarData> &newBars)
|
||||
|
|
@ -146,7 +152,8 @@ void BarChartWidget::paintEvent(QPaintEvent *)
|
|||
|
||||
// draw label below bar
|
||||
QRect labelRect(left + i * (barWidth + spacing), bottom, barWidth, LABEL_H);
|
||||
QFont f = p.font();
|
||||
// Family comes from the InterfaceDefault theme role; bold stays caller-side.
|
||||
QFont f = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
f.setBold(true);
|
||||
p.setFont(f);
|
||||
p.setPen(Qt::black);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "segmented_bar_widget.h"
|
||||
|
||||
#include "../../interface/theme_manager.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QFont>
|
||||
#include <QLinearGradient>
|
||||
|
|
@ -22,6 +24,10 @@ SegmentedBarWidget::SegmentedBarWidget(QString label, QVector<Segment> segments,
|
|||
setMinimumWidth(36);
|
||||
setMaximumWidth(50);
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
|
||||
|
||||
// The label reads the InterfaceDefault role at paint time, so a font
|
||||
// change only needs a repaint.
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, [this] { update(); });
|
||||
}
|
||||
|
||||
QSize SegmentedBarWidget::sizeHint() const
|
||||
|
|
@ -95,7 +101,8 @@ void SegmentedBarWidget::paintEvent(QPaintEvent *)
|
|||
|
||||
// draw label
|
||||
QRect labelRect(0, h - LABEL_H, w, LABEL_H);
|
||||
QFont f = p.font();
|
||||
// Family comes from the InterfaceDefault theme role; bold stays caller-side.
|
||||
QFont f = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
f.setBold(true);
|
||||
p.setFont(f);
|
||||
p.setPen(Qt::black);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "dynamic_font_size_label.h"
|
||||
|
||||
#include "../../interface/theme_manager.h"
|
||||
|
||||
#include <QFont>
|
||||
#include <QFontMetricsF>
|
||||
#include <QObject>
|
||||
|
|
@ -28,9 +30,13 @@ void DynamicFontSizeLabel::paintEvent(QPaintEvent *event)
|
|||
// QElapsedTimer timer;
|
||||
// timer.start();
|
||||
|
||||
QFont newFont = font();
|
||||
// Family follows the InterfaceDefault theme role; the fitted point size
|
||||
// stays computed from the widget geometry as before.
|
||||
QFont newFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
float fontSize = getWidgetMaximumFontSize(this, this->text());
|
||||
newFont.setPointSizeF(fontSize);
|
||||
// Preserve the caller's bold emphasis, which the role font does not carry.
|
||||
newFont.setBold(font().bold());
|
||||
setFont(newFont);
|
||||
// qDebug() << "Font size set to" << fontSize;
|
||||
|
||||
|
|
@ -40,7 +46,10 @@ void DynamicFontSizeLabel::paintEvent(QPaintEvent *event)
|
|||
|
||||
float DynamicFontSizeLabel::getWidgetMaximumFontSize(QWidget *widget, const QString &text)
|
||||
{
|
||||
QFont font = widget->font();
|
||||
// Measure with the InterfaceDefault family so the fit matches the painted font.
|
||||
QFont font = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
font.setBold(widget->font().bold());
|
||||
font.setPointSizeF(widget->font().pointSizeF());
|
||||
const QRect widgetRect = widget->contentsRect();
|
||||
const float widgetWidth = widgetRect.width();
|
||||
const float widgetHeight = widgetRect.height();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "dynamic_font_size_push_button.h"
|
||||
|
||||
#include "../../interface/theme_manager.h"
|
||||
#include "dynamic_font_size_label.h"
|
||||
|
||||
#include <QBrush>
|
||||
|
|
@ -20,10 +21,12 @@ void DynamicFontSizePushButton::paintEvent(QPaintEvent *event)
|
|||
// Call the base class paintEvent to preserve any other painting behavior
|
||||
QPushButton::paintEvent(event);
|
||||
|
||||
// Adjust the font size dynamically based on the text
|
||||
QFont newFont = font();
|
||||
// Adjust the font size dynamically based on the text. Family follows the
|
||||
// InterfaceDefault theme role; the fitted size stays computed as before.
|
||||
QFont newFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
float fontSize = DynamicFontSizeLabel::getWidgetMaximumFontSize(this, this->text());
|
||||
newFont.setPointSizeF(fontSize);
|
||||
newFont.setBold(font().bold());
|
||||
setFont(newFont);
|
||||
|
||||
// Get painter for custom painting
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
#include "home_styled_button.h"
|
||||
|
||||
#include "../../theme_manager.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QFont>
|
||||
#include <QFontMetrics>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
|
|
@ -21,6 +24,18 @@ HomeStyledButton::HomeStyledButton(const QString &text, QPair<QColor, QColor> _g
|
|||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
setMinimumHeight(25);
|
||||
setStyleSheet(generateButtonStylesheet(gradientColors));
|
||||
applyInterfaceDefaultFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, &HomeStyledButton::applyInterfaceDefaultFont);
|
||||
}
|
||||
|
||||
void HomeStyledButton::applyInterfaceDefaultFont()
|
||||
{
|
||||
// Family comes from the InterfaceDefault theme role; the 34px size and
|
||||
// bold weight previously carried by the stylesheet stay caller-side.
|
||||
QFont buttonFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
buttonFont.setPixelSize(34);
|
||||
buttonFont.setWeight(QFont::Bold);
|
||||
setFont(buttonFont);
|
||||
}
|
||||
|
||||
void HomeStyledButton::updateStylesheet(const QPair<QColor, QColor> &colors)
|
||||
|
|
@ -50,9 +65,6 @@ QString HomeStyledButton::generateButtonStylesheet(const QPair<QColor, QColor> &
|
|||
|
||||
return QString(R"(
|
||||
QPushButton {
|
||||
font-size: 34px;
|
||||
font-weight: bold;
|
||||
font-family: sans-serif, "Segoe UI", "Helvetica Neue";
|
||||
padding: 30px;
|
||||
color: white;
|
||||
border: 2px solid %1;
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ public:
|
|||
public slots:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void applyInterfaceDefaultFont();
|
||||
|
||||
private:
|
||||
QPair<QColor, QColor> gradientColors;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -289,7 +289,6 @@ QGroupBox *HomeWidget::createButtons()
|
|||
QGroupBox *box = new QGroupBox(this);
|
||||
box->setStyleSheet(R"(
|
||||
QGroupBox {
|
||||
font-size: 20px;
|
||||
color: white; /* Title text color */
|
||||
background: transparent;
|
||||
}
|
||||
|
|
@ -300,6 +299,14 @@ QGroupBox *HomeWidget::createButtons()
|
|||
subcontrol-position: top center; /* or top left / right */
|
||||
}
|
||||
)");
|
||||
// Family comes from the InterfaceDefault theme role; the 20px size stays caller-side.
|
||||
auto applyBoxFont = [box]() {
|
||||
QFont boxFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
boxFont.setPixelSize(20);
|
||||
box->setFont(boxFont);
|
||||
};
|
||||
applyBoxFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, applyBoxFont);
|
||||
box->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
QVBoxLayout *boxLayout = new QVBoxLayout;
|
||||
boxLayout->setAlignment(Qt::AlignHCenter);
|
||||
|
|
@ -463,7 +470,9 @@ void HomeWidget::paintEvent(QPaintEvent *event)
|
|||
constexpr int margin = 15;
|
||||
constexpr qreal attributionMargin = 4.0;
|
||||
|
||||
QFont attributionFont = painter.font();
|
||||
// Family comes from the InterfaceDefault theme role; the 14px sizes and
|
||||
// bold weights stay caller-side as before.
|
||||
QFont attributionFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
attributionFont.setPointSize(14);
|
||||
attributionFont.setBold(true);
|
||||
painter.setFont(attributionFont);
|
||||
|
|
@ -476,7 +485,7 @@ void HomeWidget::paintEvent(QPaintEvent *event)
|
|||
|
||||
// Card name bubble above the attribution (when enabled).
|
||||
if (!cardName.isEmpty() && SettingsCache::instance().appearance().getHomeTabDisplayCardName()) {
|
||||
QFont font = painter.font();
|
||||
QFont font = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
font.setPointSize(14);
|
||||
font.setBold(true);
|
||||
painter.setFont(font);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "first_run_wizard.h"
|
||||
|
||||
#include "../interface/theme_manager.h"
|
||||
#include "first_run_wizard_page.h"
|
||||
#include "pages/account_setup_page.h"
|
||||
#include "pages/card_database_setup_page.h"
|
||||
|
|
@ -32,9 +33,8 @@ FirstRunWizard::FirstRunWizard(QWidget *parent) : QDialog(parent)
|
|||
bannerHost = new BannerHost(this);
|
||||
|
||||
titleLabel = new QLabel(this);
|
||||
QFont titleFont = QtUtils::boldFont(titleLabel->font());
|
||||
titleFont.setPointSizeF(titleFont.pointSizeF() * 1.4);
|
||||
titleLabel->setFont(titleFont);
|
||||
applyInterfaceDefaultFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, &FirstRunWizard::applyInterfaceDefaultFont);
|
||||
|
||||
subtitleLabel = new QLabel(this);
|
||||
subtitleLabel->setWordWrap(true);
|
||||
|
|
@ -154,6 +154,16 @@ void FirstRunWizard::updateChrome()
|
|||
}
|
||||
}
|
||||
|
||||
void FirstRunWizard::applyInterfaceDefaultFont()
|
||||
{
|
||||
// Family comes from the InterfaceDefault theme role; the *1.4 size
|
||||
// multiplier and bold weight stay caller-side as before.
|
||||
QFont titleFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
titleFont.setPointSizeF(titleFont.pointSizeF() * 1.4);
|
||||
titleFont.setBold(true);
|
||||
titleLabel->setFont(titleFont);
|
||||
}
|
||||
|
||||
void FirstRunWizard::goNext()
|
||||
{
|
||||
FirstRunWizardPage *page = pages[currentIndex];
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ private slots:
|
|||
void goBack();
|
||||
void skip();
|
||||
void updateChrome();
|
||||
void applyInterfaceDefaultFont();
|
||||
|
||||
private:
|
||||
void addPage(FirstRunWizardPage *page);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "all_zones_card_amount_widget.h"
|
||||
|
||||
#include "../../theme_manager.h"
|
||||
#include "../general/display/shadow_background_label.h"
|
||||
#include "card_amount_widget.h"
|
||||
#include "libcockatrice/card/card_info.h"
|
||||
|
|
@ -67,6 +68,7 @@ AllZonesCardAmountWidget::AllZonesCardAmountWidget(QWidget *parent,
|
|||
buttonBoxSideboard->setVisible(!isToken);
|
||||
|
||||
connect(cardSizeSlider, &QSlider::valueChanged, this, &AllZonesCardAmountWidget::adjustFontSize);
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, &AllZonesCardAmountWidget::applyCardTextFont);
|
||||
|
||||
QTimer::singleShot(10, this, [this]() { adjustFontSize(this->cardSizeSlider->value()); });
|
||||
|
||||
|
|
@ -90,8 +92,9 @@ void AllZonesCardAmountWidget::adjustFontSize(int scalePercentage)
|
|||
int newFontSize = minFontSize + (scalePercentage - basePercentage) * (maxFontSize - minFontSize) / 225;
|
||||
newFontSize = std::clamp(newFontSize, minFontSize, maxFontSize);
|
||||
|
||||
// Update the font labels
|
||||
QFont zoneLabelFont = zoneLabelMainboard->font();
|
||||
// Update the font labels. The family comes from the CardText theme
|
||||
// role; the slider-driven point size stays as before.
|
||||
QFont zoneLabelFont = themeManager->appFont(AppFont::CardText);
|
||||
zoneLabelFont.setPointSize(newFontSize);
|
||||
zoneLabelMainboard->setFont(zoneLabelFont);
|
||||
zoneLabelSideboard->setFont(zoneLabelFont);
|
||||
|
|
@ -101,6 +104,11 @@ void AllZonesCardAmountWidget::adjustFontSize(int scalePercentage)
|
|||
repaint();
|
||||
}
|
||||
|
||||
void AllZonesCardAmountWidget::applyCardTextFont()
|
||||
{
|
||||
adjustFontSize(cardSizeSlider->value());
|
||||
}
|
||||
|
||||
void AllZonesCardAmountWidget::setAmounts(int mainboardAmount, int sideboardAmount, int tokensboardAmount)
|
||||
{
|
||||
buttonBoxMainboard->setAmount(mainboardAmount);
|
||||
|
|
|
|||
|
|
@ -36,6 +36,9 @@ public slots:
|
|||
void adjustFontSize(int scalePercentage);
|
||||
void setAmounts(int mainboardAmount, int sideboardAmount, int tokensboardAmount);
|
||||
|
||||
private slots:
|
||||
void applyCardTextFont();
|
||||
|
||||
private:
|
||||
QVBoxLayout *layout;
|
||||
QSlider *cardSizeSlider;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "card_amount_widget.h"
|
||||
|
||||
#include "../../theme_manager.h"
|
||||
#include "../deck_editor/deck_state_manager.h"
|
||||
#include "../general/display/dynamic_font_size_push_button.h"
|
||||
#include "deck_list_model.h"
|
||||
|
|
@ -77,6 +78,7 @@ CardAmountWidget::CardAmountWidget(QWidget *parent,
|
|||
|
||||
// Connect slider for dynamic font size adjustment
|
||||
connect(cardSizeSlider, &QSlider::valueChanged, this, &CardAmountWidget::adjustFontSize);
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, &CardAmountWidget::applyCardTextFont);
|
||||
}
|
||||
|
||||
int CardAmountWidget::getAmount()
|
||||
|
|
@ -138,8 +140,9 @@ void CardAmountWidget::adjustFontSize(int scalePercentage)
|
|||
int newFontSize = minFontSize + (scalePercentage - basePercentage) * (maxFontSize - minFontSize) / 225;
|
||||
newFontSize = std::clamp(newFontSize, minFontSize, maxFontSize);
|
||||
|
||||
// Update the font for card count label
|
||||
QFont cardCountFont = cardCountInZone->font();
|
||||
// Update the font for card count label. The family comes from the
|
||||
// CardText theme role; the slider-driven point size stays as before.
|
||||
QFont cardCountFont = themeManager->appFont(AppFont::CardText);
|
||||
cardCountFont.setPointSize(newFontSize);
|
||||
cardCountInZone->setFont(cardCountFont);
|
||||
|
||||
|
|
@ -150,6 +153,11 @@ void CardAmountWidget::adjustFontSize(int scalePercentage)
|
|||
repaint();
|
||||
}
|
||||
|
||||
void CardAmountWidget::applyCardTextFont()
|
||||
{
|
||||
adjustFontSize(cardSizeSlider->value());
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Updates the card count display in the widget.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -67,6 +67,7 @@ private slots:
|
|||
void removePrintingSideboard();
|
||||
void removePrintingTokensboard();
|
||||
void adjustFontSize(int scalePercentage);
|
||||
void applyCardTextFont();
|
||||
};
|
||||
|
||||
#endif // CARD_AMOUNT_WIDGET_H
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
#include "printing_selector_placeholder_widget.h"
|
||||
|
||||
#include "../interface/theme_manager.h"
|
||||
|
||||
#include <QFont>
|
||||
#include <QLabel>
|
||||
#include <QSizePolicy>
|
||||
#include <QVBoxLayout>
|
||||
|
|
@ -30,10 +33,12 @@ PrintingSelectorPlaceholderWidget::PrintingSelectorPlaceholderWidget(QWidget *pa
|
|||
textLabel->setStyleSheet(R"(
|
||||
QLabel {
|
||||
color: palette(mid);
|
||||
font-size: 14px;
|
||||
padding: 10px;
|
||||
}
|
||||
)");
|
||||
applyInterfaceDefaultFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this,
|
||||
&PrintingSelectorPlaceholderWidget::applyInterfaceDefaultFont);
|
||||
|
||||
mainLayout->addWidget(imageLabel);
|
||||
mainLayout->addWidget(textLabel);
|
||||
|
|
@ -44,4 +49,12 @@ PrintingSelectorPlaceholderWidget::PrintingSelectorPlaceholderWidget(QWidget *pa
|
|||
void PrintingSelectorPlaceholderWidget::retranslateUi()
|
||||
{
|
||||
textLabel->setText(tr("Select a card to view its available printings"));
|
||||
}
|
||||
|
||||
void PrintingSelectorPlaceholderWidget::applyInterfaceDefaultFont()
|
||||
{
|
||||
// Family comes from the InterfaceDefault theme role; the 14px size stays caller-side.
|
||||
QFont placeholderFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
placeholderFont.setPixelSize(14);
|
||||
textLabel->setFont(placeholderFont);
|
||||
}
|
||||
|
|
@ -14,6 +14,9 @@ class PrintingSelectorPlaceholderWidget : public QWidget
|
|||
public:
|
||||
explicit PrintingSelectorPlaceholderWidget(QWidget *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void applyInterfaceDefaultFont();
|
||||
|
||||
private:
|
||||
QVBoxLayout *mainLayout;
|
||||
QLabel *imageLabel;
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "../../client/sound_engine.h"
|
||||
#include "../../interface/card_localization.h"
|
||||
#include "../../interface/pixel_map_generator.h"
|
||||
#include "../../interface/theme_manager.h"
|
||||
#include "../../tabs/tab_supervisor.h"
|
||||
#include "../user/user_context_menu.h"
|
||||
#include "../user/user_list_manager.h"
|
||||
|
|
@ -63,6 +64,9 @@ ChatView::ChatView(TabSupervisor *_tabSupervisor, AbstractGame *_game, bool _sho
|
|||
|
||||
connect(&SettingsCache::instance(), &SettingsCache::themeChanged, this, &ChatView::adjustColorsToPalette);
|
||||
|
||||
applyChatFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, &ChatView::applyChatFont);
|
||||
|
||||
userContextMenu = new UserContextMenu(tabSupervisor, this, game);
|
||||
connect(userContextMenu, SIGNAL(openMessageDialog(QString, bool)), this, SIGNAL(openMessageDialog(QString, bool)));
|
||||
|
||||
|
|
@ -108,6 +112,16 @@ void ChatView::adjustColorsToPalette()
|
|||
QTimer::singleShot(0, this, &ChatView::refreshBlockColors);
|
||||
}
|
||||
|
||||
void ChatView::applyChatFont()
|
||||
{
|
||||
// Family comes from the ChatLog theme role; the message char formats carry
|
||||
// no family of their own, so they (and new content) follow the widget and
|
||||
// document default fonts. Weights/italics stay caller-side as before.
|
||||
const QFont chatFont = themeManager->appFont(AppFont::ChatLog);
|
||||
setFont(chatFont);
|
||||
document()->setDefaultFont(chatFont);
|
||||
}
|
||||
|
||||
void ChatView::refreshBlockColors()
|
||||
{
|
||||
QTextDocument *doc = document();
|
||||
|
|
|
|||
|
|
@ -111,6 +111,7 @@ private slots:
|
|||
void openLink(const QUrl &link);
|
||||
void actMessageClicked();
|
||||
void adjustColorsToPalette();
|
||||
void applyChatFont();
|
||||
void refreshBlockColors();
|
||||
void onScrollBarRangeChanged();
|
||||
void onScrollBarValueChanged(int value);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "user_info_box.h"
|
||||
|
||||
#include "../../interface/pixel_map_generator.h"
|
||||
#include "../../interface/theme_manager.h"
|
||||
#include "../../interface/widgets/dialogs/dlg_edit_avatar.h"
|
||||
#include "../../interface/widgets/dialogs/dlg_edit_password.h"
|
||||
#include "../../interface/widgets/dialogs/dlg_edit_user.h"
|
||||
|
|
@ -39,10 +40,8 @@
|
|||
UserInfoBox::UserInfoBox(AbstractClient *_client, bool _editable, QWidget *parent, Qt::WindowFlags flags)
|
||||
: QWidget(parent, flags), client(_client), editable(_editable)
|
||||
{
|
||||
QFont nameFont = nameLabel.font();
|
||||
nameFont.setBold(true);
|
||||
nameFont.setPointSizeF(nameFont.pointSizeF() * 1.5);
|
||||
nameLabel.setFont(nameFont);
|
||||
applyInterfaceDefaultFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, &UserInfoBox::applyInterfaceDefaultFont);
|
||||
|
||||
auto *userIconAndNameLayout = new QHBoxLayout;
|
||||
userIconAndNameLayout->addWidget(&userLevelIcon, 0, Qt::AlignCenter);
|
||||
|
|
@ -91,6 +90,16 @@ UserInfoBox::UserInfoBox(AbstractClient *_client, bool _editable, QWidget *paren
|
|||
retranslateUi();
|
||||
}
|
||||
|
||||
void UserInfoBox::applyInterfaceDefaultFont()
|
||||
{
|
||||
// Family comes from the InterfaceDefault theme role; the *1.5 size
|
||||
// multiplier and bold weight stay caller-side as before.
|
||||
QFont nameFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
nameFont.setBold(true);
|
||||
nameFont.setPointSizeF(nameFont.pointSizeF() * 1.5);
|
||||
nameLabel.setFont(nameFont);
|
||||
}
|
||||
|
||||
void UserInfoBox::retranslateUi()
|
||||
{
|
||||
realNameLabel1.setText(tr("Real Name:"));
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ private slots:
|
|||
void processEditResponse(const Response &r);
|
||||
void processPasswordResponse(const Response &r);
|
||||
void processAvatarResponse(const Response &r);
|
||||
void applyInterfaceDefaultFont();
|
||||
|
||||
void actEdit();
|
||||
void actEditInternal(const Response &r);
|
||||
|
|
|
|||
|
|
@ -142,7 +142,8 @@ public:
|
|||
p->drawEllipse(QRectF(rect.left() + 9, rect.top() + (rect.height() - 8) / 2.0, 8, 8));
|
||||
|
||||
// Game title (bold, elided)
|
||||
QFont tf = option.font;
|
||||
// Family comes from the InterfaceDefault theme role; bold stays caller-side.
|
||||
QFont tf = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
tf.setBold(true);
|
||||
p->setFont(tf);
|
||||
p->setPen(pal.color(QPalette::Text));
|
||||
|
|
@ -154,7 +155,7 @@ public:
|
|||
|
||||
// Player count
|
||||
const bool full = game.player_count() >= game.max_players();
|
||||
p->setFont(option.font);
|
||||
p->setFont(themeManager->appFont(AppFont::InterfaceDefault));
|
||||
p->setPen(full ? QColor(249, 115, 22) : pal.color(QPalette::Disabled, QPalette::Text));
|
||||
p->drawText(QRect(rect.right() - countW - 4, rect.top(), countW, rect.height()),
|
||||
Qt::AlignVCenter | Qt::AlignRight,
|
||||
|
|
@ -323,7 +324,8 @@ void UserInfoHeaderWidget::paintEvent(QPaintEvent *)
|
|||
const int tx = ax + AvatarSize + AvatarToTextGap;
|
||||
const int tw = rect.width() - tx - 8;
|
||||
|
||||
QFont nf = font();
|
||||
// Family comes from the InterfaceDefault theme role; the *1.12 size and bold stay caller-side.
|
||||
QFont nf = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
nf.setBold(true);
|
||||
nf.setPointSizeF(nf.pointSizeF() * 1.12);
|
||||
p.setFont(nf);
|
||||
|
|
@ -352,7 +354,7 @@ void UserInfoHeaderWidget::paintEvent(QPaintEvent *)
|
|||
}
|
||||
|
||||
if (!badge.text.isEmpty()) {
|
||||
QFont bf = font();
|
||||
QFont bf = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
bf.setPointSizeF(bf.pointSizeF() * 0.70);
|
||||
bf.setBold(true);
|
||||
p.setFont(bf);
|
||||
|
|
@ -369,7 +371,8 @@ void UserInfoHeaderWidget::paintEvent(QPaintEvent *)
|
|||
|
||||
// The painter font at this point depends on whether a badge was drawn
|
||||
// (badge font vs username font), so pin an explicit font for the pill.
|
||||
p.setFont(font());
|
||||
// Family follows the InterfaceDefault theme role like the rest of the popup chrome.
|
||||
p.setFont(themeManager->appFont(AppFont::InterfaceDefault));
|
||||
|
||||
// Only show the attribution when there is actually art on screen: on a
|
||||
// cache miss cardArt is null and the pill would float over the plain
|
||||
|
|
@ -398,6 +401,7 @@ UserInfoPopup::UserInfoPopup(TabSupervisor *_ts,
|
|||
// Restyle the popup chrome when the theme or its color scheme changes.
|
||||
if (themeManager) {
|
||||
connect(themeManager, &ThemeManager::themeChanged, this, &UserInfoPopup::applyTheme);
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, &UserInfoPopup::applyTheme);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -475,15 +479,24 @@ void UserInfoPopup::applyTheme()
|
|||
|
||||
separator->setStyleSheet(QStringLiteral("color:%1; margin: 0 8px;").arg(colorStr(theme.border)));
|
||||
|
||||
gamesLabel->setStyleSheet(QStringLiteral("color:%1; font-size:11px; font-weight:bold; background:transparent;")
|
||||
.arg(colorStr(theme.subText)));
|
||||
gamesLabel->setStyleSheet(QStringLiteral("color:%1; background:transparent;").arg(colorStr(theme.subText)));
|
||||
QFont gamesLabelFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
gamesLabelFont.setPixelSize(11);
|
||||
gamesLabelFont.setWeight(QFont::Bold);
|
||||
gamesLabel->setFont(gamesLabelFont);
|
||||
|
||||
refreshBtn->setStyleSheet(QStringLiteral("QPushButton{color:%1;border:none;font-size:14px;background:transparent;}"
|
||||
refreshBtn->setStyleSheet(QStringLiteral("QPushButton{color:%1;border:none;background:transparent;}"
|
||||
"QPushButton:hover{color:%2;}")
|
||||
.arg(colorStr(theme.subText), colorStr(theme.text)));
|
||||
QFont refreshFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
refreshFont.setPixelSize(14);
|
||||
refreshBtn->setFont(refreshFont);
|
||||
|
||||
gamesStatus->setStyleSheet(QStringLiteral("color:%1; font-size:11px; padding:10px; background:transparent;")
|
||||
.arg(colorStr(theme.statusText)));
|
||||
gamesStatus->setStyleSheet(
|
||||
QStringLiteral("color:%1; padding:10px; background:transparent;").arg(colorStr(theme.statusText)));
|
||||
QFont statusFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
statusFont.setPixelSize(11);
|
||||
gamesStatus->setFont(statusFont);
|
||||
|
||||
gamesView->setStyleSheet(QStringLiteral("QListView{background:%1;border:none;}"
|
||||
"QListView::item:selected{background:%2;}")
|
||||
|
|
@ -491,9 +504,12 @@ void UserInfoPopup::applyTheme()
|
|||
|
||||
closeBtn->setStyleSheet(
|
||||
QStringLiteral("QPushButton{background:%1;color:%2;"
|
||||
"border:none;border-radius:11px;font-size:10px;}"
|
||||
"border:none;border-radius:11px;}"
|
||||
"QPushButton:hover{color:%3;background:%4;}")
|
||||
.arg(colorStr(theme.closeBg), colorStr(theme.subText), colorStr(theme.text), colorStr(theme.closeHover)));
|
||||
QFont closeFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
closeFont.setPixelSize(10);
|
||||
closeBtn->setFont(closeFont);
|
||||
|
||||
header->update();
|
||||
}
|
||||
|
|
@ -508,13 +524,17 @@ static QPushButton *makeBtn(const QString &label, const QString &tip, QWidget *p
|
|||
b->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
b->setStyleSheet(QStringLiteral("QPushButton{"
|
||||
" background:%1;color:%2;border:1px solid %3;"
|
||||
" border-radius:4px;font-size:11px;padding:0 4px;"
|
||||
" border-radius:4px;padding:0 4px;"
|
||||
"}"
|
||||
"QPushButton:hover{background:%4;color:%5;}"
|
||||
"QPushButton:pressed{background:%6;}"
|
||||
"QPushButton:disabled{color:%7;border-color:%3;}")
|
||||
.arg(colorStr(t.buttonBg), colorStr(t.text), colorStr(t.buttonBorder), colorStr(t.buttonHover),
|
||||
colorStr(t.text), colorStr(t.buttonPressed), colorStr(t.buttonDisabled)));
|
||||
// Family comes from the InterfaceDefault theme role; the 11px size stays caller-side.
|
||||
QFont btnFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
btnFont.setPixelSize(11);
|
||||
b->setFont(btnFont);
|
||||
return b;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#include "user_list_painter.h"
|
||||
|
||||
#include "../../interface/pixel_map_generator.h"
|
||||
#include "../../interface/theme_manager.h"
|
||||
#include "libcockatrice/protocol/pb/serverinfo_user.pb.h"
|
||||
|
||||
#include <QAbstractScrollArea>
|
||||
|
|
@ -292,7 +293,9 @@ void UserListPainter::drawUserName(QPainter *painter,
|
|||
bool online,
|
||||
const Style &style)
|
||||
{
|
||||
QFont nameFont = option.font;
|
||||
Q_UNUSED(option);
|
||||
// Family comes from the InterfaceDefault theme role; bold stays caller-side.
|
||||
QFont nameFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
nameFont.setBold(true);
|
||||
painter->setFont(nameFont);
|
||||
|
||||
|
|
@ -351,7 +354,9 @@ void UserListPainter::drawBadges(QPainter *painter,
|
|||
return;
|
||||
}
|
||||
|
||||
QFont badgeFont = option.font;
|
||||
Q_UNUSED(option);
|
||||
// Family comes from the InterfaceDefault theme role; the *0.68 size and bold stay caller-side.
|
||||
QFont badgeFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
badgeFont.setPointSizeF(badgeFont.pointSizeF() * 0.68);
|
||||
badgeFont.setBold(true);
|
||||
painter->setFont(badgeFont);
|
||||
|
|
|
|||
|
|
@ -519,6 +519,19 @@ UserListWidget::UserListWidget(TabSupervisor *_tabSupervisor,
|
|||
userTree->viewport()->update();
|
||||
userTree->update();
|
||||
});
|
||||
// Divider headers store their font on the item, so re-apply the role
|
||||
// family here; the painter reads the role live and needs only the
|
||||
// repaint below.
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, [this] {
|
||||
QFont dividerFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
dividerFont.setBold(true);
|
||||
for (auto it = sectionItems.constBegin(); it != sectionItems.constEnd(); ++it) {
|
||||
it.value()->setFont(0, dividerFont);
|
||||
it.value()->setSizeHint(0, QSize(0, QFontMetrics(dividerFont).height() + 16));
|
||||
}
|
||||
userTree->viewport()->update();
|
||||
userTree->update();
|
||||
});
|
||||
}
|
||||
|
||||
QVBoxLayout *vbox = new QVBoxLayout;
|
||||
|
|
@ -1492,7 +1505,7 @@ QTreeWidgetItem *UserListWidget::createSectionItem(Section section)
|
|||
// They act as collapsible section headers once they have focus.
|
||||
divider->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
|
||||
|
||||
QFont font = userTree->font();
|
||||
QFont font = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
font.setBold(true);
|
||||
divider->setFont(0, font);
|
||||
// A little taller than a plain text row so the header reads as a section
|
||||
|
|
|
|||
|
|
@ -283,20 +283,11 @@ AppearanceSettingsPage::AppearanceSettingsPage()
|
|||
connect(&roundCardCornersCheckBox, &QAbstractButton::toggled, &settings.cardsDisplay(),
|
||||
&CardsDisplaySettings::setRoundCardCorners);
|
||||
|
||||
connect(&maxFontSizeForCardsEdit, qOverload<int>(&QSpinBox::valueChanged), &settings.appearance(),
|
||||
&AppearanceSettings::setMaxFontSize);
|
||||
maxFontSizeForCardsEdit.setValue(settings.appearance().getMaxFontSize());
|
||||
maxFontSizeForCardsLabel.setBuddy(&maxFontSizeForCardsEdit);
|
||||
maxFontSizeForCardsEdit.setMinimum(9);
|
||||
maxFontSizeForCardsEdit.setMaximum(100);
|
||||
|
||||
auto *cardsGrid = new QGridLayout;
|
||||
cardsGrid->addWidget(&displayCardNamesCheckBox, 0, 0, 1, 2);
|
||||
cardsGrid->addWidget(&autoRotateSidewaysLayoutCardsCheckBox, 1, 0, 1, 2);
|
||||
cardsGrid->addWidget(&cardScalingCheckBox, 2, 0, 1, 2);
|
||||
cardsGrid->addWidget(&roundCardCornersCheckBox, 3, 0, 1, 2);
|
||||
cardsGrid->addWidget(&maxFontSizeForCardsLabel, 4, 0, 1, 1);
|
||||
cardsGrid->addWidget(&maxFontSizeForCardsEdit, 4, 1, 1, 1);
|
||||
|
||||
cardsGroupBox = new QGroupBox;
|
||||
cardsGroupBox->setLayout(cardsGrid);
|
||||
|
|
@ -657,7 +648,6 @@ void AppearanceSettingsPage::retranslateUi()
|
|||
autoRotateSidewaysLayoutCardsCheckBox.setText(tr("Auto-Rotate cards with sideways layout"));
|
||||
cardScalingCheckBox.setText(tr("Scale cards on mouse over"));
|
||||
roundCardCornersCheckBox.setText(tr("Use rounded card corners"));
|
||||
maxFontSizeForCardsLabel.setText(tr("Maximum font size for information displayed on cards:"));
|
||||
|
||||
cardLayoutGroupBox->setTitle(tr("Card layout"));
|
||||
verticalCardOverlapPercentLabel.setText(
|
||||
|
|
|
|||
|
|
@ -71,8 +71,6 @@ private:
|
|||
QCheckBox autoRotateSidewaysLayoutCardsCheckBox;
|
||||
QCheckBox cardScalingCheckBox;
|
||||
QCheckBox roundCardCornersCheckBox;
|
||||
QLabel maxFontSizeForCardsLabel;
|
||||
QSpinBox maxFontSizeForCardsEdit;
|
||||
|
||||
QLabel verticalCardOverlapPercentLabel;
|
||||
QSpinBox verticalCardOverlapPercentBox;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
*/
|
||||
#include "settings_search_delegate.h"
|
||||
|
||||
#include "../interface/theme_manager.h"
|
||||
#include "settings_search_model.h"
|
||||
|
||||
#include <QBrush>
|
||||
|
|
@ -88,7 +89,8 @@ void SettingsSearchDelegate::paint(QPainter *painter,
|
|||
QRect textRect = contentRect.adjusted(iconOffset, 0, 0, 0);
|
||||
|
||||
// Breadcrumb: "Page > Group"
|
||||
QFont breadcrumbFont = option.font;
|
||||
// Family comes from the InterfaceDefault theme role; the -1 size and bold stay caller-side.
|
||||
QFont breadcrumbFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
breadcrumbFont.setPointSize(breadcrumbFont.pointSize() - 1);
|
||||
breadcrumbFont.setBold(true);
|
||||
|
||||
|
|
@ -113,7 +115,7 @@ void SettingsSearchDelegate::paint(QPainter *painter,
|
|||
yPos += 20;
|
||||
|
||||
// Setting label
|
||||
QFont labelFont = option.font;
|
||||
QFont labelFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
labelFont.setPointSize(labelFont.pointSize() + 1);
|
||||
labelFont.setBold(isSelected);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "archidekt_deck_preview_image_display_widget.h"
|
||||
|
||||
#include "../../../../../theme_manager.h"
|
||||
#include "../../../../general/display/shadow_background_label.h"
|
||||
|
||||
#include <QFont>
|
||||
|
|
@ -17,13 +18,9 @@ ArchidektDeckPreviewImageDisplayWidget::ArchidektDeckPreviewImageDisplayWidget(Q
|
|||
bottomLeftLabel = new ShadowBackgroundLabel(this, "");
|
||||
bottomRightLabel = new ShadowBackgroundLabel(this, "");
|
||||
|
||||
QFont f;
|
||||
f.setBold(true);
|
||||
f.setPointSize(16);
|
||||
topLeftLabel->setFont(f);
|
||||
topRightLabel->setFont(f);
|
||||
bottomLeftLabel->setFont(f);
|
||||
bottomRightLabel->setFont(f);
|
||||
applyCardTextFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this,
|
||||
&ArchidektDeckPreviewImageDisplayWidget::applyCardTextFont);
|
||||
|
||||
// Raise so labels appear above image
|
||||
topLeftLabel->raise();
|
||||
|
|
@ -32,6 +29,18 @@ ArchidektDeckPreviewImageDisplayWidget::ArchidektDeckPreviewImageDisplayWidget(Q
|
|||
bottomRightLabel->raise();
|
||||
}
|
||||
|
||||
void ArchidektDeckPreviewImageDisplayWidget::applyCardTextFont()
|
||||
{
|
||||
// Family comes from the CardText theme role; size and weight stay caller-side as before.
|
||||
QFont f = themeManager->appFont(AppFont::CardText);
|
||||
f.setBold(true);
|
||||
f.setPointSize(16);
|
||||
topLeftLabel->setFont(f);
|
||||
topRightLabel->setFont(f);
|
||||
bottomLeftLabel->setFont(f);
|
||||
bottomRightLabel->setFont(f);
|
||||
}
|
||||
|
||||
void ArchidektDeckPreviewImageDisplayWidget::setAspectRatio(float ratio)
|
||||
{
|
||||
aspectRatio = ratio;
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@ protected:
|
|||
*/
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
private slots:
|
||||
void applyCardTextFont();
|
||||
|
||||
private:
|
||||
float aspectRatio = 1.0f; ///< Aspect ratio to maintain for the preview image
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "edhrec_api_response_card_details_display_widget.h"
|
||||
|
||||
#include "../../../../../../theme_manager.h"
|
||||
#include "../../../../../cards/card_info_picture_widget.h"
|
||||
#include "../../../../../cards/card_size_widget.h"
|
||||
#include "../../../../../general/display/background_plate_widget.h"
|
||||
|
|
@ -9,6 +10,7 @@
|
|||
#include "edhrec_api_response_card_synergy_display_widget.h"
|
||||
#include "libcockatrice/card/database/card_database_querier.h"
|
||||
|
||||
#include <QFont>
|
||||
#include <QLabel>
|
||||
#include <QMouseEvent>
|
||||
#include <QObject>
|
||||
|
|
@ -32,7 +34,9 @@ EdhrecApiResponseCardDetailsDisplayWidget::EdhrecApiResponseCardDetailsDisplayWi
|
|||
nameLabel = new QLabel(this);
|
||||
nameLabel->setText(toDisplay.name);
|
||||
nameLabel->setAlignment(Qt::AlignHCenter);
|
||||
nameLabel->setStyleSheet("font-size: 20px; font-weight: bold");
|
||||
applyCardTextFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this,
|
||||
&EdhrecApiResponseCardDetailsDisplayWidget::applyCardTextFont);
|
||||
|
||||
inclusionDisplayWidget = new EdhrecApiResponseCardInclusionDisplayWidget(this, toDisplay);
|
||||
|
||||
|
|
@ -86,3 +90,14 @@ void EdhrecApiResponseCardDetailsDisplayWidget::actRequestPageNavigation()
|
|||
{
|
||||
emit requestUrl(toDisplay.url);
|
||||
}
|
||||
|
||||
void EdhrecApiResponseCardDetailsDisplayWidget::applyCardTextFont()
|
||||
{
|
||||
// Family comes from the CardText theme role; the 20px size and bold
|
||||
// weight previously carried by the stylesheet stay caller-side. Pixel
|
||||
// size, not point size: the stylesheet said 20px, and 20pt is ~27px.
|
||||
QFont cardFont = themeManager->appFont(AppFont::CardText);
|
||||
cardFont.setPixelSize(20);
|
||||
cardFont.setWeight(QFont::Bold);
|
||||
nameLabel->setFont(cardFont);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ public slots:
|
|||
signals:
|
||||
void requestUrl(QString url);
|
||||
|
||||
private slots:
|
||||
void applyCardTextFont();
|
||||
|
||||
private:
|
||||
EdhrecApiResponseCardDetails toDisplay;
|
||||
QVBoxLayout *layout;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "edhrec_api_response_commander_details_display_widget.h"
|
||||
|
||||
#include "../../../../../../theme_manager.h"
|
||||
#include "../../../../../cards/card_info_picture_widget.h"
|
||||
#include "../../../../../cards/card_size_widget.h"
|
||||
#include "../../api_response/cards/edhrec_commander_api_response_commander_details.h"
|
||||
|
|
@ -8,6 +9,7 @@
|
|||
#include "edhrec_commander_api_response_navigation_widget.h"
|
||||
#include "libcockatrice/card/database/card_database_querier.h"
|
||||
|
||||
#include <QFont>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QObject>
|
||||
|
|
@ -48,15 +50,16 @@ EdhrecCommanderResponseCommanderDetailsDisplayWidget::EdhrecCommanderResponseCom
|
|||
commanderName = new QLabel(this);
|
||||
commanderName->setText(commanderDetails.getName());
|
||||
commanderName->setAlignment(Qt::AlignCenter);
|
||||
commanderName->setStyleSheet("font-size: 28px; font-weight: bold");
|
||||
|
||||
label = new QLabel(this);
|
||||
label->setAlignment(Qt::AlignCenter);
|
||||
label->setStyleSheet("font-size: 16px");
|
||||
|
||||
salt = new QLabel(this);
|
||||
salt->setAlignment(Qt::AlignCenter);
|
||||
salt->setStyleSheet("font-size: 16px");
|
||||
|
||||
applyCardTextFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this,
|
||||
&EdhrecCommanderResponseCommanderDetailsDisplayWidget::applyCardTextFont);
|
||||
|
||||
cardPricesDisplayWidget = new EdhrecApiResponseCardPricesDisplayWidget(this, commanderDetails.getPrices());
|
||||
|
||||
|
|
@ -83,3 +86,19 @@ void EdhrecCommanderResponseCommanderDetailsDisplayWidget::retranslateUi()
|
|||
label->setText(commanderDetails.getLabel());
|
||||
salt->setText(tr("Salt: ") + QString::number(commanderDetails.getSalt()));
|
||||
}
|
||||
|
||||
void EdhrecCommanderResponseCommanderDetailsDisplayWidget::applyCardTextFont()
|
||||
{
|
||||
// Family comes from the CardText theme role; the sizes and the bold
|
||||
// weight previously carried by the stylesheets stay caller-side. Pixel
|
||||
// sizes, not point sizes: the stylesheets said 28px and 16px.
|
||||
QFont nameFont = themeManager->appFont(AppFont::CardText);
|
||||
nameFont.setPixelSize(28);
|
||||
nameFont.setWeight(QFont::Bold);
|
||||
commanderName->setFont(nameFont);
|
||||
|
||||
QFont detailsFont = themeManager->appFont(AppFont::CardText);
|
||||
detailsFont.setPixelSize(16);
|
||||
label->setFont(detailsFont);
|
||||
salt->setFont(detailsFont);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,9 @@ public:
|
|||
QString baseUrl);
|
||||
void retranslateUi();
|
||||
|
||||
private slots:
|
||||
void applyCardTextFont();
|
||||
|
||||
private:
|
||||
EdhrecCommanderApiResponseCommanderDetails commanderDetails;
|
||||
QHBoxLayout *layout;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
#include "edhrec_commander_api_response_bracket_navigation_widget.h"
|
||||
|
||||
#include "../../interface/theme_manager.h"
|
||||
|
||||
#include <QChar>
|
||||
#include <QFont>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
|
|
@ -25,7 +28,7 @@ EdhrecCommanderApiResponseBracketNavigationWidget::EdhrecCommanderApiResponseBra
|
|||
QString label = option.isEmpty() ? "All" : option.at(0).toUpper() + option.mid(1);
|
||||
QPushButton *optionButton = new QPushButton(label, this);
|
||||
optionButton->setMinimumHeight(84);
|
||||
optionButton->setStyleSheet("font-size: 24px");
|
||||
optionButton->setStyleSheet(QString());
|
||||
gameChangerButtons[option] = optionButton;
|
||||
layout->addWidget(optionButton, 2, i);
|
||||
connect(optionButton, &QPushButton::clicked, this, [=, this]() {
|
||||
|
|
@ -35,6 +38,10 @@ EdhrecCommanderApiResponseBracketNavigationWidget::EdhrecCommanderApiResponseBra
|
|||
});
|
||||
}
|
||||
|
||||
applyInterfaceDefaultFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this,
|
||||
&EdhrecCommanderApiResponseBracketNavigationWidget::applyInterfaceDefaultFont);
|
||||
|
||||
updateOptionButtonSelection(gameChangerButtons, "");
|
||||
|
||||
retranslateUi();
|
||||
|
|
@ -94,8 +101,18 @@ void EdhrecCommanderApiResponseBracketNavigationWidget::updateOptionButtonSelect
|
|||
const QString &selectedKey)
|
||||
{
|
||||
for (auto it = buttons.begin(); it != buttons.end(); ++it) {
|
||||
it.value()->setStyleSheet(it.key() == selectedKey
|
||||
? "background-color: lightblue; font-weight: bold; font-size: 24px;"
|
||||
: "font-size: 24px");
|
||||
const bool selected = (it.key() == selectedKey);
|
||||
it.value()->setStyleSheet(selected ? QStringLiteral("background-color: lightblue;") : QString());
|
||||
QFont buttonFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
buttonFont.setPixelSize(24);
|
||||
buttonFont.setWeight(selected ? QFont::Bold : QFont::Normal);
|
||||
it.value()->setFont(buttonFont);
|
||||
}
|
||||
}
|
||||
|
||||
void EdhrecCommanderApiResponseBracketNavigationWidget::applyInterfaceDefaultFont()
|
||||
{
|
||||
// Family comes from the InterfaceDefault theme role; the 24px size stays
|
||||
// caller-side and the selected button keeps its bold emphasis.
|
||||
updateOptionButtonSelection(gameChangerButtons, selectedGameChanger);
|
||||
}
|
||||
|
|
@ -37,6 +37,9 @@ private:
|
|||
QMap<QString, QPushButton *> gameChangerButtons;
|
||||
|
||||
void updateOptionButtonSelection(QMap<QString, QPushButton *> &buttons, const QString &selectedKey);
|
||||
|
||||
private slots:
|
||||
void applyInterfaceDefaultFont();
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BRACKET_NAVIGATION_WIDGET_H
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
#include "edhrec_commander_api_response_budget_navigation_widget.h"
|
||||
|
||||
#include "../../interface/theme_manager.h"
|
||||
|
||||
#include <QChar>
|
||||
#include <QFont>
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QPushButton>
|
||||
|
|
@ -25,7 +28,7 @@ EdhrecCommanderApiResponseBudgetNavigationWidget::EdhrecCommanderApiResponseBudg
|
|||
QString label = option.isEmpty() ? "Any" : option.at(0).toUpper() + option.mid(1);
|
||||
QPushButton *btn = new QPushButton(label, this);
|
||||
btn->setMinimumHeight(84);
|
||||
btn->setStyleSheet("font-size: 24px");
|
||||
btn->setStyleSheet(QString());
|
||||
budgetButtons[option] = btn;
|
||||
layout->addWidget(btn, 4, i);
|
||||
connect(btn, &QPushButton::clicked, this, [=, this]() {
|
||||
|
|
@ -35,6 +38,10 @@ EdhrecCommanderApiResponseBudgetNavigationWidget::EdhrecCommanderApiResponseBudg
|
|||
});
|
||||
}
|
||||
|
||||
applyInterfaceDefaultFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this,
|
||||
&EdhrecCommanderApiResponseBudgetNavigationWidget::applyInterfaceDefaultFont);
|
||||
|
||||
updateOptionButtonSelection(budgetButtons, "");
|
||||
|
||||
retranslateUi();
|
||||
|
|
@ -96,8 +103,18 @@ void EdhrecCommanderApiResponseBudgetNavigationWidget::updateOptionButtonSelecti
|
|||
const QString &selectedKey)
|
||||
{
|
||||
for (auto it = buttons.begin(); it != buttons.end(); ++it) {
|
||||
it.value()->setStyleSheet(it.key() == selectedKey
|
||||
? "background-color: lightblue; font-weight: bold; font-size: 24px;"
|
||||
: "font-size: 24px");
|
||||
const bool selected = (it.key() == selectedKey);
|
||||
it.value()->setStyleSheet(selected ? QStringLiteral("background-color: lightblue;") : QString());
|
||||
QFont buttonFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
buttonFont.setPixelSize(24);
|
||||
buttonFont.setWeight(selected ? QFont::Bold : QFont::Normal);
|
||||
it.value()->setFont(buttonFont);
|
||||
}
|
||||
}
|
||||
|
||||
void EdhrecCommanderApiResponseBudgetNavigationWidget::applyInterfaceDefaultFont()
|
||||
{
|
||||
// Family comes from the InterfaceDefault theme role; the 24px size stays
|
||||
// caller-side and the selected button keeps its bold emphasis.
|
||||
updateOptionButtonSelection(budgetButtons, selectedBudget);
|
||||
}
|
||||
|
|
@ -37,6 +37,9 @@ private:
|
|||
QMap<QString, QPushButton *> budgetButtons;
|
||||
|
||||
void updateOptionButtonSelection(QMap<QString, QPushButton *> &buttons, const QString &selectedKey);
|
||||
|
||||
private slots:
|
||||
void applyInterfaceDefaultFont();
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BUDGET_NAVIGATION_WIDGET_H
|
||||
|
|
|
|||
|
|
@ -1,9 +1,11 @@
|
|||
#include "edhrec_commander_api_response_navigation_widget.h"
|
||||
|
||||
#include "../../interface/theme_manager.h"
|
||||
#include "../../tab_edhrec_main.h"
|
||||
#include "edhrec_commander_api_response_bracket_navigation_widget.h"
|
||||
#include "edhrec_commander_api_response_budget_navigation_widget.h"
|
||||
|
||||
#include <QFont>
|
||||
#include <QGridLayout>
|
||||
#include <QObject>
|
||||
#include <QPushButton>
|
||||
|
|
@ -30,10 +32,14 @@ EdhrecCommanderApiResponseNavigationWidget::EdhrecCommanderApiResponseNavigation
|
|||
|
||||
comboPushButton = new QPushButton(this);
|
||||
comboPushButton->setMinimumHeight(84);
|
||||
comboPushButton->setStyleSheet("font-size: 24px");
|
||||
comboPushButton->setStyleSheet(QString());
|
||||
averageDeckPushButton = new QPushButton(this);
|
||||
averageDeckPushButton->setMinimumHeight(84);
|
||||
averageDeckPushButton->setStyleSheet("font-size: 24px");
|
||||
averageDeckPushButton->setStyleSheet(QString());
|
||||
|
||||
applyInterfaceDefaultFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this,
|
||||
&EdhrecCommanderApiResponseNavigationWidget::applyInterfaceDefaultFont);
|
||||
|
||||
layout->addWidget(comboPushButton, 0, 0, 1, 1);
|
||||
layout->addWidget(averageDeckPushButton, 0, 1, 1, 1);
|
||||
|
|
@ -61,6 +67,15 @@ void EdhrecCommanderApiResponseNavigationWidget::retranslateUi()
|
|||
averageDeckPushButton->setText(tr("Average Deck"));
|
||||
}
|
||||
|
||||
void EdhrecCommanderApiResponseNavigationWidget::applyInterfaceDefaultFont()
|
||||
{
|
||||
// Family comes from the InterfaceDefault theme role; the 24px size stays caller-side.
|
||||
QFont navFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
navFont.setPixelSize(24);
|
||||
comboPushButton->setFont(navFont);
|
||||
averageDeckPushButton->setFont(navFont);
|
||||
}
|
||||
|
||||
QString EdhrecCommanderApiResponseNavigationWidget::addNavigationOptionsToUrl(QString baseUrl)
|
||||
{
|
||||
if (!bracketNavigationWidget->getSelectedGameChanger().isEmpty()) {
|
||||
|
|
|
|||
|
|
@ -35,6 +35,9 @@ public slots:
|
|||
signals:
|
||||
void requestUrl(QString url);
|
||||
|
||||
private slots:
|
||||
void applyInterfaceDefaultFont();
|
||||
|
||||
private:
|
||||
QGridLayout *layout;
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include "tab_developer.h"
|
||||
|
||||
#include "../interface/theme_manager.h"
|
||||
#include "libcockatrice/protocol/pb/response.pb.h"
|
||||
|
||||
#include <QAbstractItemView>
|
||||
|
|
@ -100,6 +101,20 @@ TabDeveloper::TabDeveloper(TabSupervisor *_tabSupervisor, AbstractClient *_clien
|
|||
central->setLayout(mainLayout);
|
||||
setCentralWidget(central);
|
||||
|
||||
// Separator rows store their font on the item; re-apply the role family on
|
||||
// font changes (value cells keep the default font and need only a repaint).
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, [this] {
|
||||
QFont separatorFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
separatorFont.setBold(true);
|
||||
for (int row = 0; row < statsTable->rowCount(); ++row) {
|
||||
auto *labelItem = statsTable->item(row, 0);
|
||||
if (labelItem && !(labelItem->flags() & Qt::ItemIsSelectable)) {
|
||||
labelItem->setFont(separatorFont);
|
||||
}
|
||||
}
|
||||
statsTable->viewport()->update();
|
||||
});
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
|
|
@ -155,7 +170,8 @@ void TabDeveloper::appendSeparatorRow(const QString §ionTitle)
|
|||
const int row = statsTable->rowCount();
|
||||
statsTable->insertRow(row);
|
||||
auto *labelItem = new QTableWidgetItem(sectionTitle);
|
||||
auto font = labelItem->font();
|
||||
// Family comes from the InterfaceDefault theme role; bold stays caller-side.
|
||||
QFont font = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
font.setBold(true);
|
||||
labelItem->setFont(font);
|
||||
labelItem->setFlags(labelItem->flags() & ~Qt::ItemIsSelectable);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
#include "../../deck_loader/deck_loader.h"
|
||||
#include "../cards/card_size_widget.h"
|
||||
#include "../general/layout_containers/flow_widget.h"
|
||||
#include "../interface/theme_manager.h"
|
||||
#include "../visual_deck_storage/deck_preview/deck_preview_color_identity_filter_widget.h"
|
||||
#include "../visual_deck_storage/deck_preview/public_deck_preview_widget.h"
|
||||
#include "../visual_deck_storage/remote_public_decks_model.h"
|
||||
|
|
@ -45,7 +46,17 @@ TabPublicDecks::TabPublicDecks(TabSupervisor *_tabSupervisor, AbstractClient *_c
|
|||
cardSize = SettingsCache::instance().cardsDisplay().getVisualDeckStorageCardSize();
|
||||
|
||||
titleLabel = new QLabel(tr("Public decks of %1").arg(userName.toHtmlEscaped()), this);
|
||||
titleLabel->setFont(QtUtils::boldFont(titleLabel->font()));
|
||||
// Family comes from the InterfaceDefault theme role; bold stays caller-side.
|
||||
auto applyTitleFont = [this]() {
|
||||
titleLabel->setFont(QtUtils::boldFont(themeManager->appFont(AppFont::InterfaceDefault)));
|
||||
};
|
||||
applyTitleFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, [this, applyTitleFont] {
|
||||
applyTitleFont();
|
||||
// Preview cells paint with the live role font; repaint the grid so the
|
||||
// new family shows without waiting for a scroll or hover.
|
||||
flowWidget->update();
|
||||
});
|
||||
|
||||
auto *headerLayout = new QHBoxLayout;
|
||||
headerLayout->addWidget(titleLabel);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "tab_report.h"
|
||||
|
||||
#include "../interface/theme_manager.h"
|
||||
#include "../server/user/user_context_menu.h"
|
||||
#include "../utility/report_utils.h"
|
||||
#include "abstract_client.h"
|
||||
|
|
@ -12,6 +13,7 @@
|
|||
#include <QComboBox>
|
||||
#include <QDateTime>
|
||||
#include <QDebug>
|
||||
#include <QFont>
|
||||
#include <QGridLayout>
|
||||
#include <QGroupBox>
|
||||
#include <QHBoxLayout>
|
||||
|
|
@ -137,7 +139,8 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
|
|||
chatGroup = new QGroupBox;
|
||||
chatLogEdit = new QTextEdit;
|
||||
chatLogEdit->setReadOnly(true);
|
||||
chatLogEdit->setFont(QtUtils::monospaceFont());
|
||||
applyChatLogFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, &TabReport::applyChatLogFont);
|
||||
auto *chatLayout = new QVBoxLayout(chatGroup);
|
||||
chatLayout->setContentsMargins(4, 4, 4, 4);
|
||||
chatLayout->addWidget(chatLogEdit);
|
||||
|
|
@ -269,6 +272,11 @@ TabReport::TabReport(TabSupervisor *_tabSupervisor, AbstractClient *_client) : T
|
|||
refreshList();
|
||||
}
|
||||
|
||||
void TabReport::applyChatLogFont()
|
||||
{
|
||||
chatLogEdit->setFont(report_utils::reportLogFont());
|
||||
}
|
||||
|
||||
void TabReport::retranslateUi()
|
||||
{
|
||||
userContextMenu->retranslateUi();
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ private slots:
|
|||
void statsResponse(const Response &response);
|
||||
void reopenReport();
|
||||
void reopenResponse(const Response &response);
|
||||
void applyChatLogFont();
|
||||
|
||||
private:
|
||||
int selectedReportId() const;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "card_completer_delegate.h"
|
||||
|
||||
#include "../../interface/theme_manager.h"
|
||||
#include "../../pixel_map_generator.h"
|
||||
#include "../cards/additional_info/mana_cost_widget.h"
|
||||
#include "libcockatrice/card/database/card_database_querier.h"
|
||||
|
|
@ -182,7 +183,7 @@ void CardCompleterDelegate::drawManaSymbol(QPainter *p, QPoint centre, const QSt
|
|||
p->setBrush(Qt::NoBrush);
|
||||
p->drawEllipse(pip.adjusted(1, 1, -1, -1));
|
||||
|
||||
QFont f = QtUtils::boldFont(p->font());
|
||||
QFont f = QtUtils::boldFont(themeManager->appFont(AppFont::CardText));
|
||||
f.setPixelSize(qMax(radius - 1, 7));
|
||||
|
||||
p->setFont(f);
|
||||
|
|
@ -429,7 +430,7 @@ void CardCompleterDelegate::paint(QPainter *painter, const QStyleOptionViewItem
|
|||
const QRect nameRect = showInfoBand ? QRect(textLeft, rect.top() + 2, textWidth, 20)
|
||||
: QRect(textLeft, rect.top() + 2, textWidth, rect.height() - 4);
|
||||
|
||||
QFont f = option.font;
|
||||
QFont f = themeManager->appFont(AppFont::CardText);
|
||||
f.setPixelSize(13);
|
||||
f.setBold(true);
|
||||
|
||||
|
|
@ -451,7 +452,7 @@ void CardCompleterDelegate::paint(QPainter *painter, const QStyleOptionViewItem
|
|||
if (showInfoBand) {
|
||||
const QRect infoRect(textLeft, rect.top() + 22, textWidth, rect.height() - 24);
|
||||
|
||||
QFont f = option.font;
|
||||
QFont f = themeManager->appFont(AppFont::CardText);
|
||||
f.setPixelSize(10);
|
||||
|
||||
painter->setFont(f);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "card_completer_styler.h"
|
||||
|
||||
#include "../../interface/theme_manager.h"
|
||||
#include "../cards/card_info_picture_enlarged_widget.h"
|
||||
#include "card_completer_delegate.h"
|
||||
#include "libcockatrice/card/database/card_database_querier.h"
|
||||
|
|
@ -73,6 +74,10 @@ CardCompleterStyler::CardCompleterStyler(QCompleter *completer, QObject *parent)
|
|||
|
||||
popup->viewport()->setMouseTracking(true);
|
||||
|
||||
// The delegate reads the CardText role at paint time, so a font change
|
||||
// only needs a repaint of the popup.
|
||||
connect(themeManager, &ThemeManager::fontsChanged, popup, [popup] { popup->viewport()->update(); });
|
||||
|
||||
popup->installEventFilter(this);
|
||||
popup->viewport()->installEventFilter(this);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "report_utils.h"
|
||||
|
||||
#include "../../theme_manager.h"
|
||||
#include "libcockatrice/protocol/pb/serverinfo_report.pb.h"
|
||||
|
||||
#include <QApplication>
|
||||
|
|
@ -7,6 +8,7 @@
|
|||
#include <QChar>
|
||||
#include <QColor>
|
||||
#include <QDateTime>
|
||||
#include <QFontDatabase>
|
||||
#include <QPalette>
|
||||
#include <QSharedPointer>
|
||||
#include <QTableWidget>
|
||||
|
|
@ -19,6 +21,20 @@
|
|||
namespace report_utils
|
||||
{
|
||||
|
||||
QFont reportLogFont()
|
||||
{
|
||||
if (themeManager->hasAppFont(AppFont::ChatLog)) {
|
||||
return themeManager->appFont(AppFont::ChatLog);
|
||||
}
|
||||
QFont monoFont(QStringLiteral("monospace"));
|
||||
monoFont.setStyleHint(QFont::Monospace);
|
||||
const int systemPointSize = QFontDatabase::systemFont(QFontDatabase::GeneralFont).pointSize();
|
||||
if (systemPointSize > 0) {
|
||||
monoFont.setPointSize(systemPointSize);
|
||||
}
|
||||
return monoFont;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
QColor reportStatusColor(const QString &status)
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef REPORT_UTILS_H
|
||||
#define REPORT_UTILS_H
|
||||
|
||||
#include <QFont>
|
||||
#include <QString>
|
||||
#include <QtGlobal>
|
||||
|
||||
|
|
@ -11,6 +12,12 @@ class ServerInfo_Report;
|
|||
namespace report_utils
|
||||
{
|
||||
|
||||
/** @brief Font for the report chat-log views: the theme's ChatLog role when it
|
||||
* sets one, otherwise the monospace font these views used before the
|
||||
* role existed. Shared by the three report surfaces so they cannot
|
||||
* drift apart. */
|
||||
QFont reportLogFont();
|
||||
|
||||
QString formatReportCategory(const QString &category);
|
||||
QString formatReportTime(qint64 secondsSinceEpoch);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
#include "visual_deck_editor_placeholder_widget.h"
|
||||
|
||||
#include "../interface/theme_manager.h"
|
||||
|
||||
#include <QFont>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
#include <qnamespace.h>
|
||||
|
|
@ -28,10 +31,12 @@ VisualDeckEditorPlaceholderWidget::VisualDeckEditorPlaceholderWidget(QWidget *pa
|
|||
textLabel->setStyleSheet(R"(
|
||||
QLabel {
|
||||
color: palette(mid);
|
||||
font-size: 14px;
|
||||
padding: 10px;
|
||||
}
|
||||
)");
|
||||
applyInterfaceDefaultFont();
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this,
|
||||
&VisualDeckEditorPlaceholderWidget::applyInterfaceDefaultFont);
|
||||
|
||||
mainLayout->addWidget(imageLabel);
|
||||
mainLayout->addWidget(textLabel);
|
||||
|
|
@ -42,4 +47,12 @@ VisualDeckEditorPlaceholderWidget::VisualDeckEditorPlaceholderWidget(QWidget *pa
|
|||
void VisualDeckEditorPlaceholderWidget::retranslateUi()
|
||||
{
|
||||
textLabel->setText(tr("Add cards using the search bar or database tab to have them appear here"));
|
||||
}
|
||||
|
||||
void VisualDeckEditorPlaceholderWidget::applyInterfaceDefaultFont()
|
||||
{
|
||||
// Family comes from the InterfaceDefault theme role; the 14px size stays caller-side.
|
||||
QFont placeholderFont = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
placeholderFont.setPixelSize(14);
|
||||
textLabel->setFont(placeholderFont);
|
||||
}
|
||||
|
|
@ -15,6 +15,9 @@ public:
|
|||
explicit VisualDeckEditorPlaceholderWidget(QWidget *parent = nullptr);
|
||||
void retranslateUi();
|
||||
|
||||
private slots:
|
||||
void applyInterfaceDefaultFont();
|
||||
|
||||
private:
|
||||
QVBoxLayout *mainLayout;
|
||||
QLabel *imageLabel;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "deck_preview_tag_addition_widget.h"
|
||||
|
||||
#include "../../interface/theme_manager.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
#include <QFlags>
|
||||
|
|
@ -26,6 +28,10 @@ DeckPreviewTagAdditionWidget::DeckPreviewTagAdditionWidget(QWidget *_parent, QSt
|
|||
|
||||
// Adjust widget size
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
|
||||
// The tag text reads the InterfaceDefault role at paint time, so a font
|
||||
// change only needs a repaint.
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, [this] { update(); });
|
||||
}
|
||||
|
||||
QSize DeckPreviewTagAdditionWidget::sizeHint() const
|
||||
|
|
@ -65,8 +71,9 @@ void DeckPreviewTagAdditionWidget::paintEvent(QPaintEvent *event)
|
|||
painter.setPen(borderPen);
|
||||
painter.drawRect(rect().adjusted(0, 0, -1, -1)); // Adjust for pen width
|
||||
|
||||
// Calculate font size based on widget height
|
||||
QFont font = painter.font();
|
||||
// Calculate font size based on widget height. Family comes from the
|
||||
// InterfaceDefault theme role; the height-derived size stays as before.
|
||||
QFont font = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
int fontSize = std::max(10, height() / 2); // Ensure a minimum font size of 10
|
||||
font.setPointSize(fontSize);
|
||||
painter.setFont(font);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "deck_preview_tag_display_widget.h"
|
||||
|
||||
#include "../../interface/theme_manager.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
#include <QFlags>
|
||||
|
|
@ -41,6 +43,10 @@ DeckPreviewTagDisplayWidget::DeckPreviewTagDisplayWidget(QWidget *parent, const
|
|||
// Adjust widget size
|
||||
setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
|
||||
// The tag text reads the InterfaceDefault role at paint time, so a font
|
||||
// change only needs a repaint.
|
||||
connect(themeManager, &ThemeManager::fontsChanged, this, [this] { update(); });
|
||||
|
||||
// Connect close button to the remove signal
|
||||
// connect(closeButton, &QPushButton::clicked, this, &DeckPreviewTagDisplayWidget::tagClosed);
|
||||
}
|
||||
|
|
@ -117,8 +123,9 @@ void DeckPreviewTagDisplayWidget::paintEvent(QPaintEvent *event)
|
|||
painter.setPen(borderPen);
|
||||
painter.drawRect(rect().adjusted(0, 0, -1, -1));
|
||||
|
||||
// Calculate font size based on widget height
|
||||
QFont font = painter.font();
|
||||
// Calculate font size based on widget height. Family comes from the
|
||||
// InterfaceDefault theme role; the height-derived size stays as before.
|
||||
QFont font = themeManager->appFont(AppFont::InterfaceDefault);
|
||||
int fontSize = std::max(10, height() / 2); // Ensure a minimum font size of 10
|
||||
font.setPointSize(fontSize);
|
||||
painter.setFont(font);
|
||||
|
|
|
|||
|
|
@ -33,16 +33,6 @@ void AppearanceSettings::setStyleUserList(bool _styleUserList)
|
|||
emit styleUserListChanged();
|
||||
}
|
||||
|
||||
int AppearanceSettings::getMaxFontSize() const
|
||||
{
|
||||
return getValue("maxFontSize", QString(), QString(), 12).toInt();
|
||||
}
|
||||
|
||||
void AppearanceSettings::setMaxFontSize(int _max)
|
||||
{
|
||||
setValue(_max, "maxFontSize");
|
||||
}
|
||||
|
||||
QString AppearanceSettings::getHomeTabBackgroundSource() const
|
||||
{
|
||||
return getValue("homeTabBackgroundSource", QString(), QString(), "themed").toString();
|
||||
|
|
|
|||
|
|
@ -24,8 +24,6 @@ public:
|
|||
void setThemeName(const QString &_themeName);
|
||||
[[nodiscard]] bool getStyleUserList() const;
|
||||
void setStyleUserList(bool _styleUserList);
|
||||
[[nodiscard]] int getMaxFontSize() const;
|
||||
void setMaxFontSize(int _max);
|
||||
[[nodiscard]] QString getHomeTabBackgroundSource() const;
|
||||
void setHomeTabBackgroundSource(const QString &_backgroundSource);
|
||||
[[nodiscard]] int getHomeTabBackgroundShuffleFrequency() const;
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <QSharedPointer>
|
||||
#include <QStringList>
|
||||
#include <QStringLiteral>
|
||||
#include <QTextStream>
|
||||
#include <QVariant>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
|
@ -395,6 +396,10 @@ static void migrateAppearanceSettings(const QString &settingsPath, QSettings &gl
|
|||
{
|
||||
const QMap<QString, QString> appearanceKeyMap = {
|
||||
{"theme/name", "appearance/themeName"},
|
||||
// Retired into the theme's CardText size, but still read here so users
|
||||
// who have not migrated past global.ini keep their card text size:
|
||||
// SettingsCache runs migrateSettingsFromGlobalIni() before
|
||||
// migrateAppearanceMaxFontSizeToTheme().
|
||||
{"game/maxfontsize", "appearance/maxFontSize"},
|
||||
{"home/background", "appearance/homeTabBackgroundSource"},
|
||||
{"home/background/shuffleTimer", "appearance/homeTabBackgroundShuffleFrequency"},
|
||||
|
|
@ -424,6 +429,181 @@ static void migrateAppearanceSettings(const QString &settingsPath, QSettings &gl
|
|||
}
|
||||
}
|
||||
|
||||
static QString themesPathForSettings(const QString &settingsPath)
|
||||
{
|
||||
QSettings pathsIni(settingsPath + "paths.ini", QSettings::IniFormat);
|
||||
const QString configured = pathsIni.value("paths/themes").toString().trimmed();
|
||||
if (!configured.isEmpty()) {
|
||||
return configured;
|
||||
}
|
||||
// Default layout: <data>/themes/ sibling of <data>/settings/.
|
||||
return QDir::cleanPath(QDir(settingsPath).absoluteFilePath("../themes"));
|
||||
}
|
||||
|
||||
static bool fontsTomlHasExplicitCardTextMax(const QString &filePath)
|
||||
{
|
||||
QFile f(filePath);
|
||||
if (!f.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QString currentSection;
|
||||
QTextStream in(&f);
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine().trimmed();
|
||||
if (line.isEmpty() || line.startsWith('#') || line.startsWith(';')) {
|
||||
continue;
|
||||
}
|
||||
if (line.startsWith('[') && line.endsWith(']')) {
|
||||
currentSection = line.mid(1, line.length() - 2).trimmed();
|
||||
continue;
|
||||
}
|
||||
if (currentSection.compare("Fonts", Qt::CaseInsensitive) != 0) {
|
||||
continue;
|
||||
}
|
||||
int eq = line.indexOf('=');
|
||||
if (eq < 0) {
|
||||
continue;
|
||||
}
|
||||
QString key = line.left(eq).trimmed();
|
||||
QString value = line.mid(eq + 1).trimmed();
|
||||
for (int i = 1; i < value.size(); ++i) {
|
||||
if ((value[i] == '#' || value[i] == ';') && value[i - 1].isSpace()) {
|
||||
value = value.left(i).trimmed();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (value.size() >= 2 &&
|
||||
((value.startsWith('"') && value.endsWith('"')) || (value.startsWith('\'') && value.endsWith('\'')))) {
|
||||
value = value.mid(1, value.size() - 2).trimmed();
|
||||
}
|
||||
if (key.startsWith("AppFont::")) {
|
||||
key = key.mid(QStringLiteral("AppFont::").size());
|
||||
}
|
||||
if (key.compare("CardTextMaxSize", Qt::CaseInsensitive) == 0) {
|
||||
return true;
|
||||
}
|
||||
if (key.compare("CardText", Qt::CaseInsensitive) != 0) {
|
||||
continue;
|
||||
}
|
||||
int comma = value.lastIndexOf(',');
|
||||
if (comma < 0) {
|
||||
continue;
|
||||
}
|
||||
QString family = value.left(comma).trimmed();
|
||||
if (family.size() >= 2 &&
|
||||
((family.startsWith('"') && family.endsWith('"')) || (family.startsWith('\'') && family.endsWith('\'')))) {
|
||||
family = family.mid(1, family.size() - 2).trimmed();
|
||||
}
|
||||
bool ok = false;
|
||||
int pointSize = value.mid(comma + 1).trimmed().toInt(&ok);
|
||||
if (!ok || family.isEmpty() || pointSize <= 0) {
|
||||
continue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool seedCardTextMaxIntoThemeDir(const QString &themeDirPath, int maxSize)
|
||||
{
|
||||
if (themeDirPath.isEmpty() || maxSize <= 0) {
|
||||
return false;
|
||||
}
|
||||
QDir dir(themeDirPath);
|
||||
if (!dir.exists()) {
|
||||
return false;
|
||||
}
|
||||
const QString filePath = dir.absoluteFilePath("fonts.toml");
|
||||
if (fontsTomlHasExplicitCardTextMax(filePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QString existing;
|
||||
if (QFile::exists(filePath)) {
|
||||
QFile in(filePath);
|
||||
if (!in.open(QIODevice::ReadOnly | QIODevice::Text)) {
|
||||
return false;
|
||||
}
|
||||
existing = QString::fromUtf8(in.readAll());
|
||||
}
|
||||
|
||||
// Size-only key: seeding the CardText family here would pin it to Serif
|
||||
// for the whole board (names, player labels, the completer), which is not
|
||||
// what the retired maxFontSize setting meant. Let the family keep its
|
||||
// existing resolution and only constrain the size.
|
||||
const QString entry = QString("%1 = %2\n").arg(QStringLiteral("CardTextMaxSize"), -20).arg(maxSize);
|
||||
|
||||
QString out;
|
||||
if (existing.isEmpty()) {
|
||||
out = "[Fonts]\n" + entry + "\n";
|
||||
} else if (existing.contains("[Fonts]", Qt::CaseInsensitive)) {
|
||||
out = existing;
|
||||
if (!out.endsWith('\n')) {
|
||||
out += '\n';
|
||||
}
|
||||
out += entry;
|
||||
} else {
|
||||
out = existing;
|
||||
if (!out.endsWith('\n')) {
|
||||
out += '\n';
|
||||
}
|
||||
out += "\n[Fonts]\n" + entry + "\n";
|
||||
}
|
||||
|
||||
QFile f(filePath);
|
||||
if (!f.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate)) {
|
||||
return false;
|
||||
}
|
||||
QTextStream stream(&f);
|
||||
stream << out;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool appearanceMaxFontSizeMigrationPending(const QString &settingsPath)
|
||||
{
|
||||
if (!QFile::exists(settingsPath + "appearance.ini")) {
|
||||
return false;
|
||||
}
|
||||
QSettings appearanceIni(settingsPath + "appearance.ini", QSettings::IniFormat);
|
||||
return appearanceIni.contains("appearance/maxFontSize");
|
||||
}
|
||||
|
||||
bool SettingsMigration::migrateAppearanceMaxFontSizeToTheme(const QString &settingsPath)
|
||||
{
|
||||
if (!appearanceMaxFontSizeMigrationPending(settingsPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QSettings appearanceIni(settingsPath + "appearance.ini", QSettings::IniFormat);
|
||||
// Retired default was 12 in AppearanceSettings::getMaxFontSize; only
|
||||
// non-default values are seeded, default users rely on the theme fallback.
|
||||
const int legacy = appearanceIni.value("appearance/maxFontSize").toInt();
|
||||
if (legacy != 12 && legacy > 0) {
|
||||
const QString themesPath = themesPathForSettings(settingsPath);
|
||||
QDir themesDir(themesPath);
|
||||
const QStringList themes = themesDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
|
||||
for (const QString &theme : themes) {
|
||||
seedCardTextMaxIntoThemeDir(themesDir.absoluteFilePath(theme), legacy);
|
||||
}
|
||||
|
||||
// Shipped themes (Fabric, Leather, ...) resolve to the system theme
|
||||
// directory unless the user has already saved something for them, and
|
||||
// System/Fusion only ever exist in the user directory. Seeding existing
|
||||
// folders alone would therefore drop the retired size for every user on
|
||||
// a stock theme, so create the active theme's user directory the same
|
||||
// way ThemeManager::writableThemeDir() does for palette and font saves.
|
||||
const QString activeTheme = appearanceIni.value("appearance/themeName").toString().trimmed();
|
||||
if (!activeTheme.isEmpty() && !themesDir.exists(activeTheme) && themesDir.mkpath(activeTheme)) {
|
||||
seedCardTextMaxIntoThemeDir(themesDir.absoluteFilePath(activeTheme), legacy);
|
||||
}
|
||||
}
|
||||
|
||||
appearanceIni.remove("appearance/maxFontSize");
|
||||
appearanceIni.sync();
|
||||
return true;
|
||||
}
|
||||
|
||||
static void migrateNetworkSettings(const QString &settingsPath, QSettings &globalIni)
|
||||
{
|
||||
const QMap<QString, QString> networkKeyMap = {
|
||||
|
|
@ -821,6 +1001,10 @@ bool SettingsMigration::isMigrationPending(const QString &settingsPath)
|
|||
return true;
|
||||
}
|
||||
|
||||
if (appearanceMaxFontSizeMigrationPending(settingsPath)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
QSettings personalIni(settingsPath + "personal.ini", QSettings::IniFormat);
|
||||
if (personalIni.value("migration/legacy_complete", false).toBool()) {
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -18,6 +18,15 @@ public:
|
|||
*/
|
||||
static bool migrateGameFiltersToCamelCase(const QString &settingsPath);
|
||||
|
||||
/**
|
||||
* Moves a non-default appearance/maxFontSize value into each user-writable theme
|
||||
* directory lacking an explicit CardText max (creating/merging fonts.toml, never
|
||||
* overwriting an explicit max), then deletes the legacy key. Default (12) or absent
|
||||
* values only delete the key and create no files, since the ThemeManager fallback
|
||||
* already covers them. Idempotent, safe to run on every startup.
|
||||
*/
|
||||
static bool migrateAppearanceMaxFontSizeToTheme(const QString &settingsPath);
|
||||
|
||||
/**
|
||||
* Returns true when at least one of the two migrations would still do work, i.e. when a
|
||||
* backup of the settings directory is worth taking before they run.
|
||||
|
|
|
|||
|
|
@ -412,6 +412,15 @@ cockatrice_add_test(
|
|||
INCLUDE_DIRS
|
||||
${CMAKE_SOURCE_DIR}/cockatrice/src
|
||||
)
|
||||
cockatrice_add_test(
|
||||
NAME
|
||||
font_config_test
|
||||
SOURCES
|
||||
${CMAKE_SOURCE_DIR}/cockatrice/src/interface/theme_config.cpp
|
||||
font_config_test.cpp
|
||||
INCLUDE_DIRS
|
||||
${CMAKE_SOURCE_DIR}/cockatrice/src
|
||||
)
|
||||
cockatrice_add_test(
|
||||
NAME
|
||||
loader_local_matching_test
|
||||
|
|
|
|||
344
tests/font_config_test.cpp
Normal file
344
tests/font_config_test.cpp
Normal file
|
|
@ -0,0 +1,344 @@
|
|||
#include "interface/theme_config.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QFont>
|
||||
#include <QIODevice>
|
||||
#include <QString>
|
||||
#include <QStringLiteral>
|
||||
#include <QTemporaryDir>
|
||||
#include <QTextStream>
|
||||
#include <gtest/gtest.h>
|
||||
#include <string>
|
||||
|
||||
namespace
|
||||
{
|
||||
// Writes content to a file inside tmp, creating parents as needed.
|
||||
QString writeTempFile(QTemporaryDir &tmp, const QString &relativePath, const QString &content)
|
||||
{
|
||||
const QString filePath = QDir(tmp.path()).absoluteFilePath(relativePath);
|
||||
EXPECT_TRUE(QDir().mkpath(QFileInfo(filePath).absolutePath()));
|
||||
QFile file(filePath);
|
||||
EXPECT_TRUE(file.open(QIODevice::WriteOnly | QIODevice::Text));
|
||||
QTextStream out(&file);
|
||||
out << content;
|
||||
file.close();
|
||||
return filePath;
|
||||
}
|
||||
|
||||
QFont makeFont(const QString &family, int pointSize)
|
||||
{
|
||||
QFont font(family);
|
||||
font.setPointSize(pointSize);
|
||||
return font;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(FontConfigTest, FileNameIsFontsToml)
|
||||
{
|
||||
EXPECT_EQ(FontConfig::fileName(), QStringLiteral("fonts.toml"));
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, EmptyByDefault)
|
||||
{
|
||||
FontConfig cfg;
|
||||
EXPECT_FALSE(cfg.hasFonts());
|
||||
EXPECT_TRUE(cfg.toToml().isEmpty());
|
||||
EXPECT_EQ(cfg, FontConfig());
|
||||
EXPECT_EQ(cfg, FontConfig::fromFile("/nonexistent/path/fonts.toml"));
|
||||
EXPECT_EQ(cfg, FontConfig::fromThemeDir(QString()));
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, RoundTripPreservesFamilyAndSize)
|
||||
{
|
||||
QTemporaryDir tmp;
|
||||
ASSERT_TRUE(tmp.isValid());
|
||||
|
||||
FontConfig cfg;
|
||||
cfg.fonts[AppFont::InterfaceDefault] = makeFont("Inter", 10);
|
||||
cfg.fonts[AppFont::ChatLog] = makeFont("JetBrains Mono", 9);
|
||||
cfg.fonts[AppFont::CardText] = makeFont("Noto Serif", 11);
|
||||
cfg.fonts[AppFont::DeckList] = makeFont("Roboto", 12);
|
||||
ASSERT_TRUE(cfg.hasFonts());
|
||||
|
||||
const QString filePath = writeTempFile(tmp, "fonts.toml", cfg.toToml());
|
||||
const FontConfig loaded = FontConfig::fromFile(filePath);
|
||||
|
||||
EXPECT_EQ(loaded, cfg);
|
||||
EXPECT_EQ(loaded.fonts[AppFont::InterfaceDefault].family(), QStringLiteral("Inter"));
|
||||
EXPECT_EQ(loaded.fonts[AppFont::InterfaceDefault].pointSize(), 10);
|
||||
EXPECT_EQ(loaded.fonts[AppFont::ChatLog].family(), QStringLiteral("JetBrains Mono"));
|
||||
EXPECT_EQ(loaded.fonts[AppFont::ChatLog].pointSize(), 9);
|
||||
EXPECT_EQ(loaded.fonts[AppFont::CardText].family(), QStringLiteral("Noto Serif"));
|
||||
EXPECT_EQ(loaded.fonts[AppFont::CardText].pointSize(), 11);
|
||||
EXPECT_EQ(loaded.fonts[AppFont::DeckList].family(), QStringLiteral("Roboto"));
|
||||
EXPECT_EQ(loaded.fonts[AppFont::DeckList].pointSize(), 12);
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, RoundTripStripsWeightAndItalic)
|
||||
{
|
||||
QTemporaryDir tmp;
|
||||
ASSERT_TRUE(tmp.isValid());
|
||||
|
||||
QFont styled("Inter");
|
||||
styled.setPointSize(10);
|
||||
styled.setBold(true);
|
||||
styled.setItalic(true);
|
||||
|
||||
FontConfig cfg;
|
||||
cfg.fonts[AppFont::ChatLog] = styled;
|
||||
|
||||
const QString filePath = writeTempFile(tmp, "fonts.toml", cfg.toToml());
|
||||
const FontConfig loaded = FontConfig::fromFile(filePath);
|
||||
|
||||
ASSERT_TRUE(loaded.fonts.contains(AppFont::ChatLog));
|
||||
EXPECT_EQ(loaded.fonts[AppFont::ChatLog].family(), QStringLiteral("Inter"));
|
||||
EXPECT_EQ(loaded.fonts[AppFont::ChatLog].pointSize(), 10);
|
||||
EXPECT_FALSE(loaded.fonts[AppFont::ChatLog].bold());
|
||||
EXPECT_FALSE(loaded.fonts[AppFont::ChatLog].italic());
|
||||
EXPECT_EQ(loaded.fonts[AppFont::ChatLog], makeFont("Inter", 10));
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, ToTomlFormat)
|
||||
{
|
||||
FontConfig cfg;
|
||||
cfg.fonts[AppFont::InterfaceDefault] = makeFont("Inter", 10);
|
||||
|
||||
const QString toml = cfg.toToml();
|
||||
EXPECT_TRUE(toml.contains(QStringLiteral("[Fonts]")));
|
||||
EXPECT_TRUE(toml.contains(QStringLiteral("InterfaceDefault")));
|
||||
EXPECT_TRUE(toml.contains(QStringLiteral("\"Inter, 10\"")));
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, MalformedLinesAreSkipped)
|
||||
{
|
||||
QTemporaryDir tmp;
|
||||
ASSERT_TRUE(tmp.isValid());
|
||||
|
||||
const QString filePath = writeTempFile(tmp, "fonts.toml",
|
||||
"# a comment\n"
|
||||
"; another comment\n"
|
||||
"\n"
|
||||
"StrayBeforeSection = \"Inter, 10\"\n"
|
||||
"\n"
|
||||
"[Other]\n"
|
||||
"ChatLog = \"ShouldBeIgnored, 10\"\n"
|
||||
"\n"
|
||||
"[Fonts]\n"
|
||||
"InterfaceDefault = \"Inter, 10\"\n"
|
||||
"ChatLog = \"JetBrains Mono\", 9 # inline comment\n"
|
||||
"CardText = Noto Serif, 11\n"
|
||||
"AppFont::DeckList = \"Roboto, 12\"\n"
|
||||
"UnknownRole = \"Inter, 10\"\n"
|
||||
"QPalette::Window = \"Inter, 10\"\n"
|
||||
"NoComma = \"Inter\"\n"
|
||||
"EmptyFamily = \", 10\"\n"
|
||||
"ZeroSize = \"Inter, 0\"\n"
|
||||
"NegativeSize = \"Inter, -3\"\n"
|
||||
"NotANumber = \"Inter, big\"\n"
|
||||
"NotAnEntry\n");
|
||||
|
||||
const FontConfig loaded = FontConfig::fromFile(filePath);
|
||||
|
||||
ASSERT_TRUE(loaded.hasFonts());
|
||||
EXPECT_EQ(loaded.fonts.size(), 4);
|
||||
EXPECT_EQ(loaded.fonts[AppFont::InterfaceDefault], makeFont("Inter", 10));
|
||||
EXPECT_EQ(loaded.fonts[AppFont::ChatLog], makeFont("JetBrains Mono", 9));
|
||||
EXPECT_EQ(loaded.fonts[AppFont::CardText], makeFont("Noto Serif", 11));
|
||||
EXPECT_EQ(loaded.fonts[AppFont::DeckList], makeFont("Roboto", 12));
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, FromThemeDirReadsFontsToml)
|
||||
{
|
||||
QTemporaryDir tmp;
|
||||
ASSERT_TRUE(tmp.isValid());
|
||||
|
||||
const QString themeDir = QDir(tmp.path()).absoluteFilePath("MyTheme");
|
||||
ASSERT_TRUE(QDir().mkpath(themeDir));
|
||||
|
||||
FontConfig cfg;
|
||||
cfg.fonts[AppFont::CardText] = makeFont("Noto Serif", 11);
|
||||
writeTempFile(tmp, "MyTheme/fonts.toml", cfg.toToml());
|
||||
|
||||
const FontConfig loaded = FontConfig::fromThemeDir(themeDir);
|
||||
EXPECT_EQ(loaded, cfg);
|
||||
|
||||
// A theme directory without fonts.toml loads as empty.
|
||||
const QString bareDir = QDir(tmp.path()).absoluteFilePath("BareTheme");
|
||||
ASSERT_TRUE(QDir().mkpath(bareDir));
|
||||
EXPECT_FALSE(FontConfig::fromThemeDir(bareDir).hasFonts());
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, InequalityComparesRoles)
|
||||
{
|
||||
FontConfig left;
|
||||
left.fonts[AppFont::InterfaceDefault] = makeFont("Inter", 10);
|
||||
|
||||
FontConfig right = left;
|
||||
EXPECT_EQ(left, right);
|
||||
EXPECT_FALSE(left != right);
|
||||
|
||||
right.fonts[AppFont::InterfaceDefault] = makeFont("Inter", 11);
|
||||
EXPECT_NE(left, right);
|
||||
|
||||
right = left;
|
||||
right.fonts[AppFont::ChatLog] = makeFont("Inter", 10);
|
||||
EXPECT_NE(left, right);
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, CardTextMinRoundTrip)
|
||||
{
|
||||
QTemporaryDir tmp;
|
||||
ASSERT_TRUE(tmp.isValid());
|
||||
|
||||
FontConfig cfg;
|
||||
cfg.fonts[AppFont::CardText] = makeFont("Noto Serif", 14);
|
||||
cfg.cardTextMinSize = 3;
|
||||
ASSERT_TRUE(cfg.hasFonts());
|
||||
|
||||
const QString filePath = writeTempFile(tmp, "fonts.toml", cfg.toToml());
|
||||
const FontConfig loaded = FontConfig::fromFile(filePath);
|
||||
|
||||
EXPECT_EQ(loaded, cfg);
|
||||
EXPECT_EQ(loaded.fonts[AppFont::CardText].pointSize(), 14);
|
||||
EXPECT_EQ(loaded.cardTextMinSize, 3);
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, CardTextMinDefaultIsOmitted)
|
||||
{
|
||||
FontConfig cfg;
|
||||
cfg.fonts[AppFont::CardText] = makeFont("Noto Serif", 12);
|
||||
EXPECT_EQ(cfg.cardTextMinSize, 1);
|
||||
|
||||
const QString toml = cfg.toToml();
|
||||
EXPECT_TRUE(toml.contains(QStringLiteral("CardText")));
|
||||
EXPECT_FALSE(toml.contains(QStringLiteral("CardTextMinSize")));
|
||||
|
||||
QTemporaryDir tmp;
|
||||
ASSERT_TRUE(tmp.isValid());
|
||||
const QString filePath = writeTempFile(tmp, "fonts.toml", toml);
|
||||
EXPECT_EQ(FontConfig::fromFile(filePath).cardTextMinSize, 1);
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, MalformedMinIsSkipped)
|
||||
{
|
||||
QTemporaryDir tmp;
|
||||
ASSERT_TRUE(tmp.isValid());
|
||||
|
||||
const QString filePath = writeTempFile(tmp, "fonts.toml",
|
||||
"[Fonts]\n"
|
||||
"CardText = \"Noto Serif, 14\"\n"
|
||||
"CardTextMinSize = big\n");
|
||||
|
||||
// Each malformed value parses independently, so rewrite the file per case.
|
||||
const QStringList badValues = {"big", "0", "-3", "", "Inter, 10"};
|
||||
for (const QString &bad : badValues) {
|
||||
const QString badPath = writeTempFile(
|
||||
tmp, "bad.toml", QString("[Fonts]\nCardText = \"Noto Serif, 14\"\nCardTextMinSize = %1\n").arg(bad));
|
||||
const FontConfig loaded = FontConfig::fromFile(badPath);
|
||||
EXPECT_EQ(loaded.cardTextMinSize, 1) << "bad value: " << bad.toStdString();
|
||||
ASSERT_TRUE(loaded.fonts.contains(AppFont::CardText));
|
||||
EXPECT_EQ(loaded.fonts[AppFont::CardText].pointSize(), 14);
|
||||
}
|
||||
|
||||
// The valid file still loads.
|
||||
EXPECT_EQ(FontConfig::fromFile(filePath).cardTextMinSize, 1);
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, CardTextMaxRoundTrip)
|
||||
{
|
||||
QTemporaryDir tmp;
|
||||
ASSERT_TRUE(tmp.isValid());
|
||||
|
||||
FontConfig cfg;
|
||||
cfg.fonts[AppFont::CardText] = makeFont("Noto Serif", 14);
|
||||
cfg.cardTextMaxSize = 18;
|
||||
ASSERT_TRUE(cfg.hasFonts());
|
||||
|
||||
const QString filePath = writeTempFile(tmp, "fonts.toml", cfg.toToml());
|
||||
const FontConfig loaded = FontConfig::fromFile(filePath);
|
||||
|
||||
EXPECT_EQ(loaded, cfg);
|
||||
EXPECT_EQ(loaded.cardTextMaxSize, 18);
|
||||
EXPECT_EQ(loaded.fonts[AppFont::CardText].pointSize(), 14);
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, CardTextMaxSizeWithoutFamily)
|
||||
{
|
||||
// The retired maxFontSize setting migrates to a size-only key, so the
|
||||
// family keeps its existing resolution instead of being pinned to Serif.
|
||||
FontConfig cfg;
|
||||
cfg.cardTextMaxSize = 18;
|
||||
ASSERT_TRUE(cfg.hasFonts());
|
||||
|
||||
QTemporaryDir tmp;
|
||||
ASSERT_TRUE(tmp.isValid());
|
||||
const QString filePath = writeTempFile(tmp, "fonts.toml", cfg.toToml());
|
||||
const FontConfig loaded = FontConfig::fromFile(filePath);
|
||||
|
||||
EXPECT_TRUE(loaded.fonts.isEmpty());
|
||||
EXPECT_EQ(loaded.cardTextMaxSize, 18);
|
||||
EXPECT_EQ(loaded, cfg);
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, CardTextMaxDefaultIsOmitted)
|
||||
{
|
||||
FontConfig cfg;
|
||||
cfg.fonts[AppFont::CardText] = makeFont("Noto Serif", 12);
|
||||
EXPECT_EQ(cfg.cardTextMaxSize, 0);
|
||||
|
||||
const QString toml = cfg.toToml();
|
||||
EXPECT_FALSE(toml.contains(QStringLiteral("CardTextMaxSize")));
|
||||
|
||||
QTemporaryDir tmp;
|
||||
ASSERT_TRUE(tmp.isValid());
|
||||
const QString filePath = writeTempFile(tmp, "fonts.toml", toml);
|
||||
EXPECT_EQ(FontConfig::fromFile(filePath).cardTextMaxSize, 0);
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, MalformedMaxIsSkipped)
|
||||
{
|
||||
QTemporaryDir tmp;
|
||||
ASSERT_TRUE(tmp.isValid());
|
||||
|
||||
const QStringList badValues = {"big", "0", "-3", "", "Inter, 18"};
|
||||
for (const QString &bad : badValues) {
|
||||
const QString badPath = writeTempFile(
|
||||
tmp, "bad.toml", QString("[Fonts]\nCardText = \"Noto Serif, 14\"\nCardTextMaxSize = %1\n").arg(bad));
|
||||
const FontConfig loaded = FontConfig::fromFile(badPath);
|
||||
EXPECT_EQ(loaded.cardTextMaxSize, 0) << "bad value: " << bad.toStdString();
|
||||
ASSERT_TRUE(loaded.fonts.contains(AppFont::CardText));
|
||||
EXPECT_EQ(loaded.fonts[AppFont::CardText].pointSize(), 14);
|
||||
}
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, InequalityComparesMinSize)
|
||||
{
|
||||
FontConfig left;
|
||||
left.fonts[AppFont::CardText] = makeFont("Noto Serif", 12);
|
||||
left.cardTextMinSize = 1;
|
||||
|
||||
FontConfig right = left;
|
||||
right.cardTextMinSize = 2;
|
||||
EXPECT_NE(left, right);
|
||||
}
|
||||
|
||||
TEST(FontConfigTest, InequalityComparesMaxSize)
|
||||
{
|
||||
FontConfig left;
|
||||
left.fonts[AppFont::CardText] = makeFont("Noto Serif", 12);
|
||||
left.cardTextMaxSize = 12;
|
||||
|
||||
FontConfig right = left;
|
||||
right.cardTextMaxSize = 18;
|
||||
EXPECT_NE(left, right);
|
||||
}
|
||||
|
||||
// Every test brings its own main(): GTest is not guaranteed to be found on the build machines, and
|
||||
// the fallback then links the bare gtest library without gtest_main.
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
::testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
|
|
@ -461,19 +461,6 @@ TEST_F(SettingsDefaultsTest, Appearance_StyleUserList_Default)
|
|||
ASSERT_EQ(s.getStyleUserList(), true);
|
||||
}
|
||||
|
||||
TEST_F(SettingsDefaultsTest, Appearance_MaxFontSize_Default)
|
||||
{
|
||||
AppearanceSettings s(settingsPath, nullptr);
|
||||
ASSERT_EQ(s.getMaxFontSize(), 12);
|
||||
}
|
||||
|
||||
TEST_F(SettingsDefaultsTest, Appearance_MaxFontSize_SetAndGet)
|
||||
{
|
||||
AppearanceSettings s(settingsPath, nullptr);
|
||||
s.setMaxFontSize(14);
|
||||
ASSERT_EQ(s.getMaxFontSize(), 14);
|
||||
}
|
||||
|
||||
TEST_F(SettingsDefaultsTest, Appearance_HomeTabBackgroundSource_Default)
|
||||
{
|
||||
AppearanceSettings s(settingsPath, nullptr);
|
||||
|
|
|
|||
|
|
@ -984,6 +984,198 @@ TEST_F(SettingsMigrationTest, IsNotMigrationPendingWithoutLegacyData)
|
|||
ASSERT_FALSE(SettingsMigration::isMigrationPending(settingsPath));
|
||||
}
|
||||
|
||||
TEST_F(SettingsMigrationTest, AppearanceMaxFontSize_NonDefaultSeedsThemeAndDeletesKey)
|
||||
{
|
||||
const QString themesPath = tempDir.path() + "/themes";
|
||||
ASSERT_TRUE(QDir().mkpath(themesPath + "/MyTheme"));
|
||||
{
|
||||
QSettings paths(settingsPath + "paths.ini", QSettings::IniFormat);
|
||||
paths.setValue("paths/themes", themesPath);
|
||||
paths.sync();
|
||||
}
|
||||
{
|
||||
QSettings appearance(settingsPath + "appearance.ini", QSettings::IniFormat);
|
||||
appearance.setValue("appearance/maxFontSize", 18);
|
||||
appearance.sync();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(SettingsMigration::migrateAppearanceMaxFontSizeToTheme(settingsPath));
|
||||
|
||||
ASSERT_FALSE(readFromIni("appearance.ini", "appearance/maxFontSize").isValid());
|
||||
|
||||
const QString fontsPath = themesPath + "/MyTheme/fonts.toml";
|
||||
ASSERT_TRUE(QFile::exists(fontsPath));
|
||||
QFile f(fontsPath);
|
||||
ASSERT_TRUE(f.open(QIODevice::ReadOnly | QIODevice::Text));
|
||||
const QString content = QString::fromUtf8(f.readAll());
|
||||
EXPECT_TRUE(content.contains("CardTextMaxSize"));
|
||||
EXPECT_TRUE(content.contains("18"));
|
||||
// Size-only: the migration must not pin the family, or every CardText
|
||||
// surface switches to Serif for users who never chose it.
|
||||
EXPECT_FALSE(content.contains("Serif"));
|
||||
|
||||
ASSERT_FALSE(SettingsMigration::migrateAppearanceMaxFontSizeToTheme(settingsPath));
|
||||
}
|
||||
|
||||
TEST_F(SettingsMigrationTest, AppearanceMaxFontSize_SeedsActiveStockTheme)
|
||||
{
|
||||
// A stock theme resolves to the system directory, so there is no user theme
|
||||
// folder to seed. The migration has to create the active theme's folder,
|
||||
// otherwise the retired size is deleted without landing anywhere.
|
||||
const QString themesPath = tempDir.path() + "/themes";
|
||||
{
|
||||
QSettings paths(settingsPath + "paths.ini", QSettings::IniFormat);
|
||||
paths.setValue("paths/themes", themesPath);
|
||||
paths.sync();
|
||||
}
|
||||
{
|
||||
QSettings appearance(settingsPath + "appearance.ini", QSettings::IniFormat);
|
||||
appearance.setValue("appearance/themeName", "Fabric");
|
||||
appearance.setValue("appearance/maxFontSize", 18);
|
||||
appearance.sync();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(SettingsMigration::migrateAppearanceMaxFontSizeToTheme(settingsPath));
|
||||
|
||||
ASSERT_FALSE(readFromIni("appearance.ini", "appearance/maxFontSize").isValid());
|
||||
|
||||
const QString fontsPath = themesPath + "/Fabric/fonts.toml";
|
||||
ASSERT_TRUE(QFile::exists(fontsPath));
|
||||
QFile f(fontsPath);
|
||||
ASSERT_TRUE(f.open(QIODevice::ReadOnly | QIODevice::Text));
|
||||
const QString content = QString::fromUtf8(f.readAll());
|
||||
EXPECT_TRUE(content.contains("CardTextMaxSize"));
|
||||
EXPECT_TRUE(content.contains("18"));
|
||||
}
|
||||
|
||||
TEST_F(SettingsMigrationTest, AppearanceMaxFontSize_KeepsExistingActiveTheme)
|
||||
{
|
||||
const QString themesPath = tempDir.path() + "/themes";
|
||||
ASSERT_TRUE(QDir().mkpath(themesPath + "/Fabric"));
|
||||
{
|
||||
QFile f(themesPath + "/Fabric/fonts.toml");
|
||||
ASSERT_TRUE(f.open(QIODevice::WriteOnly | QIODevice::Text));
|
||||
QTextStream out(&f);
|
||||
out << "[Fonts]\nCardText = \"Inter, 10\"\n";
|
||||
}
|
||||
{
|
||||
QSettings paths(settingsPath + "paths.ini", QSettings::IniFormat);
|
||||
paths.setValue("paths/themes", themesPath);
|
||||
paths.sync();
|
||||
}
|
||||
{
|
||||
QSettings appearance(settingsPath + "appearance.ini", QSettings::IniFormat);
|
||||
appearance.setValue("appearance/themeName", "Fabric");
|
||||
appearance.setValue("appearance/maxFontSize", 18);
|
||||
appearance.sync();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(SettingsMigration::migrateAppearanceMaxFontSizeToTheme(settingsPath));
|
||||
|
||||
QFile f(themesPath + "/Fabric/fonts.toml");
|
||||
ASSERT_TRUE(f.open(QIODevice::ReadOnly | QIODevice::Text));
|
||||
const QString content = QString::fromUtf8(f.readAll());
|
||||
EXPECT_TRUE(content.contains("Inter, 10"));
|
||||
EXPECT_FALSE(content.contains("18"));
|
||||
}
|
||||
|
||||
TEST_F(SettingsMigrationTest, AppearanceMaxFontSize_DefaultDeletesKeyWithoutFiles)
|
||||
{
|
||||
const QString themesPath = tempDir.path() + "/themes";
|
||||
ASSERT_TRUE(QDir().mkpath(themesPath + "/MyTheme"));
|
||||
{
|
||||
QSettings paths(settingsPath + "paths.ini", QSettings::IniFormat);
|
||||
paths.setValue("paths/themes", themesPath);
|
||||
paths.sync();
|
||||
}
|
||||
{
|
||||
QSettings appearance(settingsPath + "appearance.ini", QSettings::IniFormat);
|
||||
appearance.setValue("appearance/maxFontSize", 12);
|
||||
appearance.sync();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(SettingsMigration::migrateAppearanceMaxFontSizeToTheme(settingsPath));
|
||||
ASSERT_FALSE(readFromIni("appearance.ini", "appearance/maxFontSize").isValid());
|
||||
ASSERT_FALSE(QFile::exists(themesPath + "/MyTheme/fonts.toml"));
|
||||
}
|
||||
|
||||
TEST_F(SettingsMigrationTest, AppearanceMaxFontSize_DoesNotOverwriteExplicitMax)
|
||||
{
|
||||
const QString themesPath = tempDir.path() + "/themes";
|
||||
ASSERT_TRUE(QDir().mkpath(themesPath + "/MyTheme"));
|
||||
{
|
||||
QFile f(themesPath + "/MyTheme/fonts.toml");
|
||||
ASSERT_TRUE(f.open(QIODevice::WriteOnly | QIODevice::Text));
|
||||
QTextStream out(&f);
|
||||
out << "[Fonts]\nCardText = \"Inter, 10\"\n";
|
||||
}
|
||||
{
|
||||
QSettings paths(settingsPath + "paths.ini", QSettings::IniFormat);
|
||||
paths.setValue("paths/themes", themesPath);
|
||||
paths.sync();
|
||||
}
|
||||
{
|
||||
QSettings appearance(settingsPath + "appearance.ini", QSettings::IniFormat);
|
||||
appearance.setValue("appearance/maxFontSize", 18);
|
||||
appearance.sync();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(SettingsMigration::migrateAppearanceMaxFontSizeToTheme(settingsPath));
|
||||
|
||||
QFile f(themesPath + "/MyTheme/fonts.toml");
|
||||
ASSERT_TRUE(f.open(QIODevice::ReadOnly | QIODevice::Text));
|
||||
const QString content = QString::fromUtf8(f.readAll());
|
||||
EXPECT_TRUE(content.contains("10"));
|
||||
EXPECT_FALSE(content.contains("18"));
|
||||
}
|
||||
|
||||
TEST_F(SettingsMigrationTest, AppearanceMaxFontSize_MergesWithOtherRoles)
|
||||
{
|
||||
const QString themesPath = tempDir.path() + "/themes";
|
||||
ASSERT_TRUE(QDir().mkpath(themesPath + "/MyTheme"));
|
||||
{
|
||||
QFile f(themesPath + "/MyTheme/fonts.toml");
|
||||
ASSERT_TRUE(f.open(QIODevice::WriteOnly | QIODevice::Text));
|
||||
QTextStream out(&f);
|
||||
out << "[Fonts]\nInterfaceDefault = \"Inter, 10\"\n";
|
||||
}
|
||||
{
|
||||
QSettings paths(settingsPath + "paths.ini", QSettings::IniFormat);
|
||||
paths.setValue("paths/themes", themesPath);
|
||||
paths.sync();
|
||||
}
|
||||
{
|
||||
QSettings appearance(settingsPath + "appearance.ini", QSettings::IniFormat);
|
||||
appearance.setValue("appearance/maxFontSize", 20);
|
||||
appearance.sync();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(SettingsMigration::migrateAppearanceMaxFontSizeToTheme(settingsPath));
|
||||
|
||||
QFile f(themesPath + "/MyTheme/fonts.toml");
|
||||
ASSERT_TRUE(f.open(QIODevice::ReadOnly | QIODevice::Text));
|
||||
const QString content = QString::fromUtf8(f.readAll());
|
||||
EXPECT_TRUE(content.contains("InterfaceDefault"));
|
||||
EXPECT_TRUE(content.contains("CardTextMaxSize"));
|
||||
EXPECT_TRUE(content.contains("20"));
|
||||
}
|
||||
|
||||
TEST_F(SettingsMigrationTest, AppearanceMaxFontSize_AbsentKeyDoesNothing)
|
||||
{
|
||||
ASSERT_FALSE(SettingsMigration::migrateAppearanceMaxFontSizeToTheme(settingsPath));
|
||||
}
|
||||
|
||||
TEST_F(SettingsMigrationTest, IsMigrationPendingWhenMaxFontSizePresent)
|
||||
{
|
||||
{
|
||||
QSettings appearance(settingsPath + "appearance.ini", QSettings::IniFormat);
|
||||
appearance.setValue("appearance/maxFontSize", 18);
|
||||
appearance.sync();
|
||||
}
|
||||
|
||||
ASSERT_TRUE(SettingsMigration::isMigrationPending(settingsPath));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char **argv)
|
||||
|
|
|
|||
2
vcpkg
2
vcpkg
|
|
@ -1 +1 @@
|
|||
Subproject commit 9eec002df1cd109f8f104cd966a763daf9751489
|
||||
Subproject commit 9e593bb18ea69cc5095e012465dcd675a822ed0d
|
||||
Loading…
Add table
Add a link
Reference in a new issue