mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 01:23:24 -08:00
Compare commits
22 commits
71fd913058
...
28c200e950
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
28c200e950 | ||
|
|
60f7710d9f | ||
|
|
d26a7b213f | ||
|
|
a7e151d871 | ||
|
|
2593824e93 | ||
|
|
4e78edf794 | ||
|
|
1bdd43d921 | ||
|
|
77ed6550f9 | ||
|
|
b57cd77986 | ||
|
|
4a60b2fde2 | ||
|
|
134c830d42 | ||
|
|
d34bb81884 | ||
|
|
c72192fd81 | ||
|
|
9588e1960d | ||
|
|
fd2a99e897 | ||
|
|
dc4aa19d23 | ||
|
|
ada8f399f1 | ||
|
|
bc09ec6afe | ||
|
|
bfb53c5def | ||
|
|
381dd21e8c | ||
|
|
c5b776ca46 | ||
|
|
dd7ee3541c |
107 changed files with 2154 additions and 232 deletions
|
|
@ -71,6 +71,8 @@ if(WIN32 OR USE_VCPKG)
|
|||
)
|
||||
# Qt path set by user or env var
|
||||
if(QTDIR
|
||||
OR QTDIR32
|
||||
OR QTDIR64
|
||||
OR DEFINED ENV{QTDIR}
|
||||
OR DEFINED ENV{QTDIR32}
|
||||
OR DEFINED ENV{QTDIR64}
|
||||
|
|
@ -236,13 +238,13 @@ else()
|
|||
set(_lib_suffix 32)
|
||||
endif()
|
||||
|
||||
if(DEFINED QTDIR${_lib_suffix})
|
||||
if(NOT "${QTDIR${_lib_suffix}}" STREQUAL "")
|
||||
list(APPEND CMAKE_PREFIX_PATH "${QTDIR${_lib_suffix}}")
|
||||
elseif(DEFINED QTDIR)
|
||||
elseif(NOT "${QTDIR}" STREQUAL "")
|
||||
list(APPEND CMAKE_PREFIX_PATH "${QTDIR}")
|
||||
elseif(DEFINED ENV{QTDIR${_lib_suffix}})
|
||||
elseif(NOT "$ENV{QTDIR${_lib_suffix}}" STREQUAL "")
|
||||
list(APPEND CMAKE_PREFIX_PATH "$ENV{QTDIR${_lib_suffix}}")
|
||||
elseif(DEFINED ENV{QTDIR})
|
||||
elseif(NOT "$ENV{QTDIR}" STREQUAL "")
|
||||
list(APPEND CMAKE_PREFIX_PATH "$ENV{QTDIR}")
|
||||
endif()
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Find a compatible Qt version
|
||||
# Inputs: WITH_SERVER, WITH_CLIENT, WITH_ORACLE
|
||||
# Optional Input: QT6_DIR -- Hint as to where Qt6 lives on the system
|
||||
# Optional Input: Qt6_DIR -- Directory containing Qt6Config.cmake
|
||||
# Output: COCKATRICE_QT_VERSION_NAME -- Example values: Qt6
|
||||
# Output: SERVATRICE_QT_MODULES
|
||||
# Output: COCKATRICE_QT_MODULES
|
||||
|
|
@ -57,7 +57,17 @@ find_package(
|
|||
QUIET HINTS ${Qt6_DIR}
|
||||
)
|
||||
if(NOT Qt6_FOUND)
|
||||
message(FATAL_ERROR "No suitable version of Qt was found")
|
||||
set(_QT_DIAGNOSTIC "")
|
||||
if(Qt6_NOT_FOUND_MESSAGE)
|
||||
set(_QT_DIAGNOSTIC "\nQt package diagnostic: ${Qt6_NOT_FOUND_MESSAGE}")
|
||||
endif()
|
||||
message(FATAL_ERROR
|
||||
"No suitable version of Qt was found. Qt 6.4.2 or newer with these components is required: "
|
||||
"${REQUIRED_QT_COMPONENTS};Linguist.\n"
|
||||
"Set QTDIR or CMAKE_PREFIX_PATH to the Qt installation prefix, or Qt6_DIR to the directory "
|
||||
"containing Qt6Config.cmake."
|
||||
"${_QT_DIAGNOSTIC}"
|
||||
)
|
||||
endif()
|
||||
set(COCKATRICE_QT_VERSION_NAME Qt6)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -15,14 +15,18 @@ static const QString ARCHIDEKT_SUFFIX = "/?format=json";
|
|||
static const QString MOXFIELD_BASE = "https://api.moxfield.com/v2/decks/all/";
|
||||
static const QString MOXFIELD_SUFFIX = "/";
|
||||
|
||||
static const QString DECKSTATS_BASE = "https://deckstats.net/decks/";
|
||||
static const QString DECKSTATS_SUFFIX = "?include_comments=1&export_mtgarena=1";
|
||||
|
||||
static const QString MANABOX_BASE = "https://cloud.manabox.app/decks/";
|
||||
|
||||
bool parseDeckUrl(const QString &url, ParsedDeckInfo &outInfo)
|
||||
{
|
||||
static QRegularExpression rxTappedOut("tappedout\\.net/(?:mtg-decks/)?([^/?#]+)");
|
||||
static QRegularExpression rxArchidekt("archidekt\\.com/decks/(\\d+)");
|
||||
static QRegularExpression rxMoxfield("moxfield\\.com/decks/([a-zA-Z0-9_-]+)");
|
||||
static QRegularExpression rxDeckstats("deckstats\\.net/decks/(\\d+/[a-zA-Z0-9_-]+)");
|
||||
static QRegularExpression rxManabox("manabox\\.app/decks/([a-zA-Z0-9_-]+)");
|
||||
|
||||
QRegularExpressionMatch match;
|
||||
|
||||
|
|
@ -49,11 +53,18 @@ bool parseDeckUrl(const QString &url, ParsedDeckInfo &outInfo)
|
|||
return true;
|
||||
} else if ((match = rxDeckstats.match(url)).hasMatch()) {
|
||||
QString deckPath = match.captured(1);
|
||||
outInfo = ParsedDeckInfo{.baseUrl = "https://deckstats.net/decks/",
|
||||
outInfo = ParsedDeckInfo{.baseUrl = DECKSTATS_BASE,
|
||||
.deckID = deckPath,
|
||||
.fullUrl = "https://deckstats.net/decks/" + deckPath + DECKSTATS_SUFFIX,
|
||||
.fullUrl = DECKSTATS_BASE + deckPath + DECKSTATS_SUFFIX,
|
||||
.provider = DeckProvider::Deckstats};
|
||||
return true;
|
||||
} else if ((match = rxManabox.match(url)).hasMatch()) {
|
||||
QString deckPath = match.captured(1);
|
||||
outInfo = ParsedDeckInfo{.baseUrl = MANABOX_BASE,
|
||||
.deckID = deckPath,
|
||||
.fullUrl = MANABOX_BASE + deckPath,
|
||||
.provider = DeckProvider::Manabox};
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ enum class DeckProvider
|
|||
Archidekt,
|
||||
Moxfield,
|
||||
Deckstats,
|
||||
Manabox,
|
||||
Unknown
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -8,12 +8,19 @@
|
|||
#define INTERFACE_JSON_DECK_PARSER_H
|
||||
|
||||
#include "../../../interface/deck_loader/card_node_function.h"
|
||||
#include "libcockatrice/deck_list/tree/inner_deck_list_node.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
#include <QJsonObject>
|
||||
#include <QList>
|
||||
#include <QLoggingCategory>
|
||||
#include <QString>
|
||||
#include <QTextStream>
|
||||
#include <libcockatrice/card/import/card_name_normalizer.h>
|
||||
#include <libcockatrice/deck_list/deck_list.h>
|
||||
|
||||
inline Q_LOGGING_CATEGORY(InterfaceJsonDeckParserLog, "interface_json_deck_parser");
|
||||
|
||||
class IJsonDeckParser
|
||||
{
|
||||
public:
|
||||
|
|
@ -32,9 +39,6 @@ public:
|
|||
QString deckName = obj.value("name").toString();
|
||||
QString deckDescription = obj.value("description").toString();
|
||||
|
||||
deckList.setName(deckName);
|
||||
deckList.setComments(deckDescription);
|
||||
|
||||
QString outputText;
|
||||
QTextStream outStream(&outputText);
|
||||
|
||||
|
|
@ -50,8 +54,14 @@ public:
|
|||
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
||||
}
|
||||
|
||||
outStream.flush();
|
||||
outStream.seek(0);
|
||||
deckList.loadFromStream_Plain(outStream, false, CardNameNormalizer());
|
||||
deckList.setName(deckName);
|
||||
deckList.setComments(deckDescription);
|
||||
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
||||
deckList.setName(deckName);
|
||||
deckList.setComments(deckDescription);
|
||||
|
||||
return deckList;
|
||||
}
|
||||
|
|
@ -67,9 +77,6 @@ public:
|
|||
QString deckName = obj.value("name").toString();
|
||||
QString deckDescription = obj.value("description").toString();
|
||||
|
||||
deckList.setName(deckName);
|
||||
deckList.setComments(deckDescription);
|
||||
|
||||
QString outputText;
|
||||
QTextStream outStream(&outputText);
|
||||
|
||||
|
|
@ -97,8 +104,14 @@ public:
|
|||
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
||||
}
|
||||
|
||||
outStream.flush();
|
||||
outStream.seek(0);
|
||||
deckList.loadFromStream_Plain(outStream, false, CardNameNormalizer());
|
||||
deckList.setName(deckName);
|
||||
deckList.setComments(deckDescription);
|
||||
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
||||
deckList.setName(deckName);
|
||||
deckList.setComments(deckDescription);
|
||||
|
||||
QJsonObject commandersObj = obj.value("commanders").toObject();
|
||||
if (!commandersObj.isEmpty()) {
|
||||
|
|
@ -114,6 +127,113 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// Moxfield stores Oathbreaker signature spells in their own board,
|
||||
// separate from both mainboard and commanders. They are playable deck
|
||||
// cards, but must not replace the Oathbreaker as the banner card.
|
||||
const QJsonObject signatureSpells = obj.value("signatureSpells").toObject();
|
||||
for (auto it = signatureSpells.begin(); it != signatureSpells.end(); ++it) {
|
||||
const QJsonObject entry = it.value().toObject();
|
||||
const QJsonObject card = entry.value("card").toObject();
|
||||
const QString name = card.value("name").toString();
|
||||
const int quantity = entry.value("quantity").toInt();
|
||||
if (name.isEmpty() || quantity <= 0) {
|
||||
continue;
|
||||
}
|
||||
const QString set = card.value("set").toString().toUpper();
|
||||
const QString collectorNumber = card.value("cn").toString();
|
||||
const QString providerId = card.value("scryfall_id").toString();
|
||||
deckList.addCards(name, quantity, DECK_ZONE_MAIN, -1, set, collectorNumber, providerId);
|
||||
}
|
||||
|
||||
return deckList;
|
||||
}
|
||||
};
|
||||
|
||||
class ManaboxJsonParser : public IJsonDeckParser
|
||||
{
|
||||
enum BoardType : quint32
|
||||
{
|
||||
MainBoard = 0,
|
||||
SideBoard = 1,
|
||||
Commander = 2,
|
||||
MaybeBoard = 3,
|
||||
};
|
||||
|
||||
public:
|
||||
DeckList parse(const QJsonObject &obj) override
|
||||
{
|
||||
DeckList deckList;
|
||||
|
||||
QString deckName = obj.value("name").toString();
|
||||
|
||||
QString outputText;
|
||||
QString mainboardText;
|
||||
QString sideboardText;
|
||||
QTextStream mainboardStream(&mainboardText);
|
||||
QTextStream sideboardStream(&sideboardText);
|
||||
QTextStream outStream(&outputText);
|
||||
|
||||
auto commanderList = QList<QJsonObject>();
|
||||
auto maybeboardList = QList<QJsonObject>();
|
||||
for (auto entry : obj.value("cards").toArray()) {
|
||||
auto card = entry.toObject();
|
||||
|
||||
auto collectorNumber = card.value("collectorNumber").toString();
|
||||
auto cardName = card.value("name").toString();
|
||||
auto boardType = static_cast<BoardType>(card.value("boardCategory").toInt());
|
||||
auto setName = card.value("setId").toString();
|
||||
auto quantity = card.value("quantity").toInt();
|
||||
auto providerId = card.value("scryfallId").toString();
|
||||
|
||||
switch (boardType) {
|
||||
case MainBoard:
|
||||
mainboardStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber
|
||||
<< '\n';
|
||||
break;
|
||||
case SideBoard:
|
||||
sideboardStream << "SB: " << quantity << ' ' << cardName << " (" << setName << ") "
|
||||
<< collectorNumber << '\n';
|
||||
break;
|
||||
case MaybeBoard:
|
||||
maybeboardList.append(card);
|
||||
break;
|
||||
case Commander:
|
||||
commanderList.append(card);
|
||||
break;
|
||||
default:
|
||||
qCWarning(InterfaceJsonDeckParserLog)
|
||||
<< "Unknown ManaBox Zone" << card.value("boardCategory").toInt() << "for" << cardName;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
outStream << mainboardText << sideboardText;
|
||||
|
||||
deckList.loadFromStream_Plain(outStream, false, CardNameNormalizer());
|
||||
deckList.setName(deckName);
|
||||
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
||||
|
||||
for (const auto &maybeboardCard : maybeboardList) {
|
||||
QString cardName = maybeboardCard.value("name").toString();
|
||||
QString setName = maybeboardCard.value("setId").toString().toUpper();
|
||||
QString collectorNumber = maybeboardCard.value("collectorNumber").toString();
|
||||
QString providerId = maybeboardCard.value("scryfallId").toString();
|
||||
|
||||
for (int x = 0; x < maybeboardCard.value("quantity").toInt(); x++) {
|
||||
deckList.addCard(cardName, DECK_ZONE_MAYBEBOARD, -1, setName, collectorNumber, providerId);
|
||||
}
|
||||
}
|
||||
for (const auto &commanderCard : commanderList) {
|
||||
|
||||
QString commanderName = commanderCard.value("name").toString();
|
||||
QString setName = commanderCard.value("setId").toString().toUpper();
|
||||
QString collectorNumber = commanderCard.value("collectorNumber").toString();
|
||||
QString providerId = commanderCard.value("scryfallId").toString();
|
||||
|
||||
deckList.setBannerCard({commanderName, providerId});
|
||||
deckList.addCard(commanderName, DECK_ZONE_MAIN, -1, setName, collectorNumber, providerId);
|
||||
}
|
||||
|
||||
return deckList;
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
#include "shortcut_treeview.h"
|
||||
|
||||
#include "../../interface/theme_manager.h"
|
||||
#include "cache_settings.h"
|
||||
#include "shortcuts_settings.h"
|
||||
|
||||
|
|
@ -93,7 +94,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>
|
||||
|
|
@ -202,7 +204,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"
|
||||
|
|
@ -154,7 +155,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,7 +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");
|
||||
// Family comes from the DeckList theme role; pixel sizes/weights unchanged.
|
||||
QFont f = themeManager->appFont(AppFont::DeckList);
|
||||
f.setStyleHint(QFont::Serif);
|
||||
f.setPixelSize(24);
|
||||
f.setWeight(QFont::Bold);
|
||||
|
|
@ -292,7 +293,8 @@ QList<QPair<int, int>> DeckViewCardContainer::getRowsAndCols() const
|
|||
|
||||
int DeckViewCardContainer::getCardTypeTextWidth() const
|
||||
{
|
||||
QFont f("Serif");
|
||||
// Family comes from the DeckList theme role; pixel size/weight unchanged.
|
||||
QFont f = themeManager->appFont(AppFont::DeckList);
|
||||
f.setStyleHint(QFont::Serif);
|
||||
f.setPixelSize(16);
|
||||
f.setWeight(QFont::Bold);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <QSharedPointer>
|
||||
#include <QTimer>
|
||||
#include <QUrl>
|
||||
#include <QtGlobal>
|
||||
|
||||
class ExactCard;
|
||||
|
||||
|
|
@ -38,32 +39,94 @@ void CardPictureLoaderStatusBar::cleanOldEntries()
|
|||
if (!loadLog || !loadLog->popup) {
|
||||
return;
|
||||
}
|
||||
for (CardPictureLoaderRequestStatusDisplayWidget *statusDisplayWidget :
|
||||
loadLog->popup->findChildren<CardPictureLoaderRequestStatusDisplayWidget *>()) {
|
||||
|
||||
const QDateTime now = QDateTime::currentDateTime();
|
||||
// Removing an entry mutates the log, so walk a copy of it.
|
||||
const QList<CardPictureLoaderRequestStatusDisplayWidget *> entries = logEntries;
|
||||
for (CardPictureLoaderRequestStatusDisplayWidget *statusDisplayWidget : entries) {
|
||||
statusDisplayWidget->queryElapsedSeconds();
|
||||
if (statusDisplayWidget->getFinished() &&
|
||||
QDateTime::fromString(statusDisplayWidget->getStartTime()).secsTo(QDateTime::currentDateTime()) > 10) {
|
||||
loadLog->removeSettingsWidget(statusDisplayWidget);
|
||||
progressBar->setMaximum(progressBar->maximum() - 1);
|
||||
progressBar->setValue(progressBar->value() - 1);
|
||||
if (!statusDisplayWidget->getFinished()) {
|
||||
continue;
|
||||
}
|
||||
if (QDateTime::fromString(statusDisplayWidget->getStartTime()).secsTo(now) > LOG_ENTRY_LIFETIME_SECS) {
|
||||
removeLogEntry(statusDisplayWidget);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CardPictureLoaderStatusBar::addQueuedImageLoad(const QUrl &url, const ExactCard &card, const QString &setName)
|
||||
{
|
||||
loadLog->addSettingsWidget(new CardPictureLoaderRequestStatusDisplayWidget(loadLog, url, card, setName));
|
||||
if (logEntries.size() >= MAX_LOG_ENTRIES) {
|
||||
trimLog();
|
||||
}
|
||||
|
||||
auto *entry = new CardPictureLoaderRequestStatusDisplayWidget(loadLog, url, card, setName);
|
||||
loadLog->addSettingsWidget(entry);
|
||||
logEntries.append(entry);
|
||||
entriesByUrl.insert(entry->getUrl(), entry);
|
||||
progressBar->setMaximum(progressBar->maximum() + 1);
|
||||
}
|
||||
|
||||
void CardPictureLoaderStatusBar::addSuccessfulImageLoad(const QUrl &url)
|
||||
{
|
||||
progressBar->setValue(progressBar->value() + 1);
|
||||
for (CardPictureLoaderRequestStatusDisplayWidget *statusDisplayWidget :
|
||||
loadLog->popup->findChildren<CardPictureLoaderRequestStatusDisplayWidget *>()) {
|
||||
if (statusDisplayWidget->getUrl() == url.toString()) {
|
||||
statusDisplayWidget->queryElapsedSeconds();
|
||||
statusDisplayWidget->setFinished();
|
||||
const QList<CardPictureLoaderRequestStatusDisplayWidget *> entries = entriesByUrl.values(url.toString());
|
||||
if (entries.isEmpty()) {
|
||||
// The entry may already have been dropped from the log; the download
|
||||
// itself still succeeded, there is just nothing left to mark.
|
||||
return;
|
||||
}
|
||||
|
||||
int finishedEntries = 0;
|
||||
for (CardPictureLoaderRequestStatusDisplayWidget *statusDisplayWidget : entries) {
|
||||
if (statusDisplayWidget->getFinished()) {
|
||||
continue;
|
||||
}
|
||||
statusDisplayWidget->queryElapsedSeconds();
|
||||
statusDisplayWidget->setFinished();
|
||||
++finishedEntries;
|
||||
}
|
||||
|
||||
// The bar counts the entries currently in the log, so only entries that are
|
||||
// still listed move it.
|
||||
progressBar->setValue(progressBar->value() + finishedEntries);
|
||||
}
|
||||
|
||||
void CardPictureLoaderStatusBar::trimLog()
|
||||
{
|
||||
if (logEntries.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Prefer evicting an entry that has already finished; only fall back to an
|
||||
// in-flight request when the whole log is still pending.
|
||||
CardPictureLoaderRequestStatusDisplayWidget *toRemove = nullptr;
|
||||
for (CardPictureLoaderRequestStatusDisplayWidget *entry : logEntries) {
|
||||
if (entry->getFinished()) {
|
||||
toRemove = entry;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
removeLogEntry(toRemove != nullptr ? toRemove : logEntries.constFirst());
|
||||
}
|
||||
|
||||
void CardPictureLoaderStatusBar::removeLogEntry(CardPictureLoaderRequestStatusDisplayWidget *entry)
|
||||
{
|
||||
if (entry == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
logEntries.removeOne(entry);
|
||||
entriesByUrl.remove(entry->getUrl(), entry);
|
||||
|
||||
// The progress bar's maximum counts the entries currently in the log and
|
||||
// its value the finished ones, so dropping an entry moves both counters back.
|
||||
// Move the value first: a maximum of 0 turns the bar into a busy indicator and
|
||||
// resets its value.
|
||||
if (entry->getFinished()) {
|
||||
progressBar->setValue(qMax(0, progressBar->value() - 1));
|
||||
}
|
||||
progressBar->setMaximum(qMax(0, progressBar->maximum() - 1));
|
||||
|
||||
loadLog->removeSettingsWidget(entry);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
#ifndef PICTURE_LOADER_STATUS_BAR_H
|
||||
#define PICTURE_LOADER_STATUS_BAR_H
|
||||
|
||||
#include <QList>
|
||||
#include <QMultiHash>
|
||||
#include <QString>
|
||||
#include <QWidget>
|
||||
#include <qtmetamacros.h>
|
||||
|
||||
class CardPictureLoaderRequestStatusDisplayWidget;
|
||||
class ExactCard;
|
||||
class QHBoxLayout;
|
||||
class QProgressBar;
|
||||
|
|
@ -21,11 +24,20 @@ class SettingsButtonWidget;
|
|||
* - Shows overall progress of image downloads.
|
||||
* - Maintains a log of individual requests via a popup (SettingsButtonWidget).
|
||||
* - Cleans up finished request entries automatically after a delay.
|
||||
*
|
||||
* The log is a diagnostic view, not a queue: it keeps at most MAX_LOG_ENTRIES
|
||||
* entries and indexes them by URL, so a burst of requests stays O(1) per event
|
||||
* instead of scanning every entry the popup holds.
|
||||
*/
|
||||
class CardPictureLoaderStatusBar : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/** Entries kept in the log; older ones are evicted as new requests arrive. */
|
||||
static constexpr int MAX_LOG_ENTRIES = 50;
|
||||
/** Seconds a finished entry stays in the log before it is cleaned up. */
|
||||
static constexpr int LOG_ENTRY_LIFETIME_SECS = 10;
|
||||
|
||||
/**
|
||||
* @brief Constructs a status bar with progress bar and log button.
|
||||
* @param parent Parent widget
|
||||
|
|
@ -55,10 +67,28 @@ public slots:
|
|||
void cleanOldEntries();
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Evicts the oldest finished entry (or the oldest entry if none finished)
|
||||
* until the log fits within MAX_LOG_ENTRIES.
|
||||
*/
|
||||
void trimLog();
|
||||
|
||||
/**
|
||||
* @brief Removes one entry from the log, its URL index and the popup, and keeps
|
||||
* the progress bar counters in step with the entries that remain.
|
||||
* @param entry Entry to remove
|
||||
*/
|
||||
void removeLogEntry(CardPictureLoaderRequestStatusDisplayWidget *entry);
|
||||
|
||||
QHBoxLayout *layout; ///< Horizontal layout containing progress bar and log button
|
||||
QProgressBar *progressBar; ///< Progress bar showing overall download progress
|
||||
SettingsButtonWidget *loadLog; ///< Popup log showing individual request statuses
|
||||
QTimer *cleaner; ///< Timer for periodically cleaning old log entries
|
||||
QList<CardPictureLoaderRequestStatusDisplayWidget *> logEntries; ///< Logged requests, oldest first
|
||||
// A URL can back several live entries: a request parked for a deferred retry is re-queued while
|
||||
// its first entry is still pending, so a completion must finish every entry for that URL.
|
||||
QMultiHash<QString, CardPictureLoaderRequestStatusDisplayWidget *>
|
||||
entriesByUrl; ///< Log entries indexed by their URL for O(1) completion lookup
|
||||
};
|
||||
|
||||
#endif // PICTURE_LOADER_STATUS_BAR_H
|
||||
|
|
|
|||
|
|
@ -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->appFont(AppFont::DeckList).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->appFont(AppFont::DeckList).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->appFont(AppFont::DeckList).family()});
|
||||
charFormat.setFontPointSize(14);
|
||||
charFormat.setFontWeight(QFont::Bold);
|
||||
|
||||
|
|
@ -640,7 +645,8 @@ void DeckLoader::printDeckList(QPrinter *printer, const DeckList &deckList)
|
|||
{
|
||||
QTextDocument doc;
|
||||
|
||||
QFont font("Serif");
|
||||
// Family comes from the DeckList theme role; the print sizes/weights below stay unchanged.
|
||||
QFont font = themeManager->appFont(AppFont::DeckList);
|
||||
font.setStyleHint(QFont::Serif);
|
||||
doc.setDefaultFont(font);
|
||||
|
||||
|
|
@ -648,6 +654,7 @@ void DeckLoader::printDeckList(QPrinter *printer, const DeckList &deckList)
|
|||
|
||||
QTextBlockFormat headerBlockFormat;
|
||||
QTextCharFormat headerCharFormat;
|
||||
headerCharFormat.setFontFamilies({themeManager->appFont(AppFont::DeckList).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());
|
||||
|
|
|
|||
127
cockatrice/src/interface/palette_editor/font_grid_widget.cpp
Normal file
127
cockatrice/src/interface/palette_editor/font_grid_widget.cpp
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
#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 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);
|
||||
|
||||
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(); });
|
||||
|
||||
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(); });
|
||||
|
||||
fontRows[role] = {label, familyCombo, sizeSpin};
|
||||
}
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
|
||||
void FontGridWidget::loadFonts(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[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);
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
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.sizeSpin->setToolTip(tr("Point size"));
|
||||
}
|
||||
}
|
||||
43
cockatrice/src/interface/palette_editor/font_grid_widget.h
Normal file
43
cockatrice/src/interface/palette_editor/font_grid_widget.h
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
#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;
|
||||
};
|
||||
|
||||
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,32 @@ 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);
|
||||
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 +185,7 @@ 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] { 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 +195,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 +235,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").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 +278,19 @@ void PaletteEditorDialog::loadSchemes()
|
|||
}
|
||||
}
|
||||
|
||||
void PaletteEditorDialog::loadFonts()
|
||||
{
|
||||
// Same user-dir > system-dir fallback ThemeManager uses: the shipped
|
||||
// fonts.toml may live in the system theme directory rather than the
|
||||
// resolved (user) theme directory.
|
||||
FontConfig cfg = ThemeManager::loadFontConfig(themeDirPath);
|
||||
if (!cfg.hasFonts()) {
|
||||
cfg = ThemeManager::loadDefaultFontConfig(themeDirPath, themeName);
|
||||
}
|
||||
savedFontConfig = cfg;
|
||||
fontGrid->loadFonts(cfg);
|
||||
}
|
||||
|
||||
void PaletteEditorDialog::seedAccentFromScheme(const QString &scheme)
|
||||
{
|
||||
QColor seed = workingConfig.value(scheme).colors.value(QPalette::Active).value(QPalette::Highlight);
|
||||
|
|
@ -258,6 +321,7 @@ void PaletteEditorDialog::onGenerateFromAccent(const QColor &accent, int intensi
|
|||
void PaletteEditorDialog::onApply()
|
||||
{
|
||||
themeManager->previewPalette(paletteGrid->currentPaletteConfig(), loadedScheme);
|
||||
themeManager->previewFonts(fontGrid->currentFontConfig());
|
||||
}
|
||||
|
||||
void PaletteEditorDialog::onSave()
|
||||
|
|
@ -308,6 +372,17 @@ void PaletteEditorDialog::onSave()
|
|||
savedConfig[it.key()] = it.value();
|
||||
}
|
||||
|
||||
// Persist the shared per-theme fonts when they changed.
|
||||
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;
|
||||
}
|
||||
|
||||
themeManager->reloadCurrentTheme();
|
||||
accept();
|
||||
}
|
||||
|
|
@ -316,6 +391,11 @@ 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);
|
||||
seedAccentFromScheme(loadedScheme);
|
||||
}
|
||||
|
||||
|
|
@ -350,6 +430,18 @@ 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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
|
@ -38,8 +39,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 +52,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,6 +76,10 @@ 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;
|
||||
|
||||
QTimer *autoApplyTimer = nullptr;
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -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,150 @@ QPalette PaletteConfig::apply(QPalette base) const
|
|||
}
|
||||
|
||||
return base;
|
||||
}
|
||||
}
|
||||
|
||||
bool FontConfig::hasFonts() const
|
||||
{
|
||||
return !fonts.isEmpty();
|
||||
}
|
||||
|
||||
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 (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();
|
||||
}
|
||||
|
||||
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,33 @@ 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"
|
||||
* @endcode
|
||||
*/
|
||||
struct FontConfig
|
||||
{
|
||||
QMap<AppFont::Role, QFont> fonts;
|
||||
|
||||
bool operator==(const FontConfig &rhs) const
|
||||
{
|
||||
return fonts == rhs.fonts;
|
||||
}
|
||||
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,44 @@ 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, so the result is
|
||||
// identical to before. The report dialogs that used to hardcode monospace
|
||||
// ask for it explicitly (report_utils::reportLogFont), and the counter
|
||||
// painters that used to hardcode Serif ask for it through cardTextFont().
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
||||
void ThemeManager::themeChangedSlot()
|
||||
{
|
||||
QString themeName = SettingsCache::instance().getThemeName();
|
||||
|
|
@ -642,6 +741,28 @@ void ThemeManager::themeChangedSlot()
|
|||
|
||||
applyStyleAndPalette(themeName, themeCfg, palette, activeScheme);
|
||||
|
||||
// ── Load fonts: shared per theme, no light/dark split ───────────────────
|
||||
FontConfig fonts = loadFontConfig(dirPath);
|
||||
if (!fonts.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.
|
||||
const QString sysFontPath = QDir(systemThemesBasePath()).absoluteFilePath(themeName);
|
||||
if (sysFontPath != dirPath) {
|
||||
fonts = loadFontConfig(sysFontPath);
|
||||
}
|
||||
}
|
||||
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,25 @@ 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 a per-role fallback (serif basis
|
||||
* for CardText, the application font for the remaining roles). */
|
||||
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 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;
|
||||
|
||||
QBrush &getBgBrush(Role zone);
|
||||
QBrush getExtraBgBrush(Role zone, int zoneId = 0);
|
||||
|
|
@ -144,6 +171,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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -97,6 +100,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,8 +178,10 @@ void CardInfoPictureWithTextOverlayWidget::paintEvent(QPaintEvent *event)
|
|||
return;
|
||||
}
|
||||
|
||||
// Calculate the optimal font size
|
||||
QFont font = painter.font();
|
||||
// Calculate the optimal font size. The family comes from the CardText
|
||||
// theme role; the fontSize member stays the starting size and the
|
||||
// shrink-to-fit logic below is unchanged.
|
||||
QFont font = themeManager->appFont(AppFont::CardText);
|
||||
int optimalFontSize = fontSize; // Start with the user-defined font size
|
||||
const QFontMetrics baseMetrics(font);
|
||||
int textWidth = pixmapRect.width();
|
||||
|
|
@ -284,7 +296,7 @@ QSize CardInfoPictureWithTextOverlayWidget::minimumSizeHint() const
|
|||
const QSize pixmapSize = pixmap.isNull() ? QSize(0, 0) : pixmap.size();
|
||||
|
||||
// Get the font metrics for the overlay text
|
||||
QFont font;
|
||||
QFont font = themeManager->appFont(AppFont::CardText);
|
||||
font.setPointSize(fontSize);
|
||||
const QFontMetrics fontMetrics(font);
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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); }")
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@
|
|||
#include <QPushButton>
|
||||
#include <QSet>
|
||||
#include <QSharedPointer>
|
||||
#include <QSignalBlocker>
|
||||
#include <QSize>
|
||||
#include <QSizePolicy>
|
||||
#include <QSplitter>
|
||||
|
|
@ -187,10 +188,17 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
|||
formatLabel = new QLabel(this);
|
||||
|
||||
formatComboBox = new QComboBox(this);
|
||||
formatComboBox->setObjectName("deckFormatComboBox");
|
||||
formatComboBox->addItem(tr("Loading Database..."));
|
||||
formatComboBox->setEnabled(false); // Disable until loaded
|
||||
|
||||
commanderBracketWidget = new CommanderBracketWidget(this);
|
||||
connect(formatComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||
formatComboBox->setPlaceholderText(QString());
|
||||
formatComboBox->setToolTip(QString());
|
||||
deckStateManager->setFormat(index >= 0 ? formatComboBox->itemData(index).toString() : QString());
|
||||
commanderBracketWidget->setDeck(deckStateManager->getDeckListShared());
|
||||
});
|
||||
|
||||
commentsLabel = new QLabel();
|
||||
commentsLabel->setObjectName("commentsLabel");
|
||||
|
|
@ -355,6 +363,9 @@ void DeckEditorDeckDockWidget::initializeFormats()
|
|||
{
|
||||
QStringList allFormats = CardDatabaseManager::query()->getAllFormatsWithCount().keys();
|
||||
|
||||
// Rebuilding the list is a view update, not a user edit. In particular,
|
||||
// clear() emits currentIndexChanged(-1), which must not clear the deck.
|
||||
const QSignalBlocker blocker(formatComboBox);
|
||||
formatComboBox->clear(); // Remove "Loading Database..."
|
||||
formatComboBox->setEnabled(true);
|
||||
|
||||
|
|
@ -364,28 +375,25 @@ void DeckEditorDeckDockWidget::initializeFormats()
|
|||
formatComboBox->addItem(formatName, formatName); // store the raw key in itemData
|
||||
}
|
||||
|
||||
QString format = deckStateManager->getMetadata().gameFormat;
|
||||
if (!format.isEmpty()) {
|
||||
formatComboBox->setCurrentIndex(formatComboBox->findData(format));
|
||||
} else {
|
||||
// Ensure no selection is visible initially
|
||||
formatComboBox->setCurrentIndex(-1);
|
||||
}
|
||||
connect(formatComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||
QString formatKey;
|
||||
if (index >= 0) {
|
||||
formatKey = formatComboBox->itemData(index).toString();
|
||||
deckStateManager->setFormat(formatKey);
|
||||
} else {
|
||||
deckStateManager->setFormat(""); // clear format if deselected
|
||||
}
|
||||
|
||||
commanderBracketWidget->setDeck(deckStateManager->getDeckListShared());
|
||||
});
|
||||
syncFormatSelection();
|
||||
|
||||
commanderBracketWidget->setDeck(deckStateManager->getDeckListShared());
|
||||
}
|
||||
|
||||
void DeckEditorDeckDockWidget::syncFormatSelection()
|
||||
{
|
||||
if (!formatComboBox->isEnabled()) {
|
||||
return;
|
||||
}
|
||||
const QSignalBlocker blocker(formatComboBox);
|
||||
const QString format = deckStateManager->getMetadata().gameFormat;
|
||||
const int index = format.isEmpty() ? -1 : formatComboBox->findData(format);
|
||||
const QString unavailable = index < 0 && !format.isEmpty() ? tr("Unavailable: %1").arg(format) : QString();
|
||||
formatComboBox->setPlaceholderText(unavailable);
|
||||
formatComboBox->setToolTip(unavailable);
|
||||
formatComboBox->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
ExactCard DeckEditorDeckDockWidget::getCurrentCard()
|
||||
{
|
||||
QModelIndex current = deckView->selectionModel()->currentIndex();
|
||||
|
|
@ -596,9 +604,7 @@ void DeckEditorDeckDockWidget::syncDisplayWidgetsToModel()
|
|||
updatePlaymatLabel();
|
||||
updateHash();
|
||||
|
||||
formatComboBox->blockSignals(true);
|
||||
formatComboBox->setCurrentIndex(formatComboBox->findData(deckStateManager->getMetadata().gameFormat));
|
||||
formatComboBox->blockSignals(false);
|
||||
syncFormatSelection();
|
||||
|
||||
commanderBracketWidget->setDeck(deckStateManager->getDeckListShared());
|
||||
|
||||
|
|
@ -762,18 +768,6 @@ void DeckEditorDeckDockWidget::actSwapSelection()
|
|||
update();
|
||||
}
|
||||
|
||||
void DeckEditorDeckDockWidget::actDecrementCard(const ExactCard &card, QString zoneName)
|
||||
{
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
if (card.getInfo().getIsToken()) {
|
||||
zoneName = DECK_ZONE_TOKENS;
|
||||
}
|
||||
|
||||
deckStateManager->decrementCard(card, zoneName);
|
||||
}
|
||||
|
||||
void DeckEditorDeckDockWidget::actDecrementSelection()
|
||||
{
|
||||
auto selectedRows = getSelectedCardNodeSourceIndices();
|
||||
|
|
@ -1054,6 +1048,7 @@ void DeckEditorDeckDockWidget::retranslateUi()
|
|||
commentsLabel->setText(tr("&Comments:"));
|
||||
activeGroupCriteriaLabel->setText(tr("Group by:"));
|
||||
formatLabel->setText(tr("Format:"));
|
||||
syncFormatSelection();
|
||||
commanderBracketWidget->retranslateUi();
|
||||
|
||||
hashLabel1->setText(tr("Hash:"));
|
||||
|
|
|
|||
|
|
@ -70,7 +70,6 @@ public slots:
|
|||
void syncDisplayWidgetsToModel();
|
||||
void actAddCard(const ExactCard &card, const QString &zoneName);
|
||||
void actIncrementSelection();
|
||||
void actDecrementCard(const ExactCard &card, QString zoneName);
|
||||
void actDecrementSelection();
|
||||
void actSwapCard(const ExactCard &card, const QString &zoneName);
|
||||
void actSwapSelection();
|
||||
|
|
@ -111,6 +110,7 @@ private:
|
|||
DeckListModel *getModel() const;
|
||||
[[nodiscard]] QModelIndexList getSelectedCardNodeSourceIndices() const;
|
||||
void offsetCountAtIndex(const QModelIndex &idx, bool isIncrement);
|
||||
void syncFormatSelection();
|
||||
|
||||
void addMoveToZoneMenu(QMenu *menu, const QModelIndex &sourceCardIndex, const QString ¤tBoardName);
|
||||
void addChangeBoardMenu(QMenu *menu, const QString &zoneName);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "deck_list_style_proxy.h"
|
||||
|
||||
#include "../../theme_manager.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QColor>
|
||||
#include <QFont>
|
||||
|
|
@ -20,7 +22,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,15 +211,15 @@ QModelIndex DeckStateManager::addCard(const ExactCard &card, const QString &zone
|
|||
return {};
|
||||
}
|
||||
|
||||
QString zone = card.getInfo().getIsToken() ? DECK_ZONE_TOKENS : zoneName;
|
||||
QString targetZone = card.getInfo().getIsToken() ? DECK_ZONE_TOKENS : zoneName;
|
||||
|
||||
CardSetPtr set = card.getPrinting().getSet();
|
||||
QString setName = set ? set->getCorrectedShortName() : "";
|
||||
|
||||
QString reason =
|
||||
tr("Added (%1): %2 (%3) %4").arg(zone, card.getName(), setName, card.getPrinting().getProperty("num"));
|
||||
tr("Added (%1): %2 (%3) %4").arg(targetZone, card.getName(), setName, card.getPrinting().getProperty("num"));
|
||||
|
||||
QModelIndex idx = modifyDeck(reason, [&card, &zone](auto model) { return model->addCard(card, zone); });
|
||||
QModelIndex idx = modifyDeck(reason, [&card, &targetZone](auto model) { return model->addCard(card, targetZone); });
|
||||
|
||||
if (idx.isValid()) {
|
||||
emit focusIndexChanged(idx, true);
|
||||
|
|
@ -234,10 +234,22 @@ QModelIndex DeckStateManager::decrementCard(const ExactCard &card, const QString
|
|||
return {};
|
||||
}
|
||||
|
||||
QString targetZone = zoneName;
|
||||
|
||||
QString providerId = card.getPrinting().getUuid();
|
||||
QString collectorNumber = card.getPrinting().getProperty("num");
|
||||
|
||||
QModelIndex idx = deckListModel->findCard(card.getName(), zoneName, providerId, collectorNumber);
|
||||
QModelIndex idx = deckListModel->findCard(card.getName(), targetZone, providerId, collectorNumber);
|
||||
|
||||
// Tokens are usually added to the token zone, but it is possible for imported/hand-edited
|
||||
// decks to contain them in the main or sideboards. This is why we only try to remove the
|
||||
// token from the token zone if it does not exist in the given zone, allowing us to still
|
||||
// remove it from there.
|
||||
if (!idx.isValid() && card.getInfo().getIsToken() && targetZone != DECK_ZONE_TOKENS) {
|
||||
targetZone = DECK_ZONE_TOKENS;
|
||||
idx = deckListModel->findCard(card.getName(), targetZone, providerId, collectorNumber);
|
||||
}
|
||||
|
||||
if (!idx.isValid()) {
|
||||
return {};
|
||||
}
|
||||
|
|
@ -249,7 +261,7 @@ QModelIndex DeckStateManager::decrementCard(const ExactCard &card, const QString
|
|||
}
|
||||
|
||||
// old index is no longer safe since rows could have been removed
|
||||
QModelIndex newIdx = deckListModel->findCard(card.getName(), zoneName, providerId, collectorNumber);
|
||||
QModelIndex newIdx = deckListModel->findCard(card.getName(), targetZone, providerId, collectorNumber);
|
||||
if (newIdx.isValid()) {
|
||||
emit focusIndexChanged(newIdx, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -188,17 +188,18 @@ public:
|
|||
///@}
|
||||
|
||||
/**
|
||||
* @brief Adds the given card to the given zone.
|
||||
* @brief Adds the given card to the given zone. Tokens always go to DECK_ZONE_TOKENS, ignoring the given zone.
|
||||
* Saves the operation to history if successful.
|
||||
*
|
||||
* @param card The card to add
|
||||
* @param zoneName The zone to add the card to
|
||||
* @param zoneName The zone to add the card to if the card is not a token
|
||||
* @return The index of the added card
|
||||
*/
|
||||
QModelIndex addCard(const ExactCard &card, const QString &zoneName);
|
||||
|
||||
/**
|
||||
* @brief Removes 1 copy of the given card from the given zone.
|
||||
* If the card is a token and is not in the given zone, then it is removed from DECK_ZONE_TOKENS instead.
|
||||
* Saves the operation to history if successful.
|
||||
*
|
||||
* @param card The card to remove
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include <QNetworkReply>
|
||||
#include <QNetworkRequest>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
#include <QUrl>
|
||||
#include <QVBoxLayout>
|
||||
|
|
@ -33,6 +34,7 @@
|
|||
|
||||
class QWidget;
|
||||
|
||||
static const QStringList SUPPORTED_PROVIDERS = {"Archidekt", "Deckstats", "ManaBox", "Moxfield", "TappedOut"};
|
||||
DlgLoadDeckFromWebsite::DlgLoadDeckFromWebsite(QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
nam = NetworkManagerFactory::create(this);
|
||||
|
|
@ -41,6 +43,7 @@ DlgLoadDeckFromWebsite::DlgLoadDeckFromWebsite(QWidget *parent) : QDialog(parent
|
|||
setLayout(layout);
|
||||
|
||||
instructionLabel = new QLabel(this);
|
||||
instructionLabel->setWordWrap(true);
|
||||
layout->addWidget(instructionLabel);
|
||||
|
||||
urlEdit = new QLineEdit(this);
|
||||
|
|
@ -64,8 +67,8 @@ DlgLoadDeckFromWebsite::DlgLoadDeckFromWebsite(QWidget *parent) : QDialog(parent
|
|||
|
||||
void DlgLoadDeckFromWebsite::retranslateUi()
|
||||
{
|
||||
instructionLabel->setText(tr("Paste a link to a decklist site here to import it.\n(Archidekt, Deckstats, Moxfield, "
|
||||
"and TappedOut are supported.)"));
|
||||
instructionLabel->setText(tr("Paste a link to a decklist site here to import it.") + "\n" +
|
||||
tr("Supported services: %1").arg(SUPPORTED_PROVIDERS.join(", ")));
|
||||
}
|
||||
|
||||
bool DlgLoadDeckFromWebsite::testValidUrl()
|
||||
|
|
@ -84,8 +87,8 @@ void DlgLoadDeckFromWebsite::accept()
|
|||
if (!jsonParser && info.provider != DeckProvider::Deckstats && info.provider != DeckProvider::TappedOut) {
|
||||
qCWarning(DlgLoadDeckFromWebsiteLog) << "No parser found for provider";
|
||||
QMessageBox::warning(this, tr("Load Deck from Website"),
|
||||
tr("No parser available for this deck provider.\n (Archidekt, Deckstats, Moxfield, "
|
||||
"and TappedOut are supported.)"));
|
||||
tr("No parser available for this deck provider.") + "\n" +
|
||||
tr("Supported services: %1").arg(SUPPORTED_PROVIDERS.join(", ")));
|
||||
QDialog::reject();
|
||||
return;
|
||||
}
|
||||
|
|
@ -152,6 +155,7 @@ void DlgLoadDeckFromWebsite::accept()
|
|||
"https://archidekt.com/decks/9999999\n"
|
||||
"https://deckstats.net/decks/99999/9999999-your-deck-name/en\n"
|
||||
"https://moxfield.com/decks/XYZxx-XYZ99Yyy-xyzXzzz\n"
|
||||
"https://manabox.app/decks/XYZxxa-YZ99Yyyx_yzXzzz\n"
|
||||
"https://tappedout.net/mtg-decks/your-deck-name/"));
|
||||
QDialog::reject();
|
||||
}
|
||||
|
|
@ -164,7 +168,9 @@ QSharedPointer<IJsonDeckParser> DlgLoadDeckFromWebsite::createParserForProvider(
|
|||
return QSharedPointer<IJsonDeckParser>(new ArchidektJsonParser());
|
||||
case DeckProvider::Moxfield:
|
||||
return QSharedPointer<IJsonDeckParser>(new MoxfieldJsonParser());
|
||||
case DeckProvider::Manabox:
|
||||
return QSharedPointer<IJsonDeckParser>(new ManaboxJsonParser());
|
||||
default:
|
||||
return QSharedPointer<IJsonDeckParser>(nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -146,7 +148,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>
|
||||
|
|
@ -95,7 +97,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);
|
||||
|
|
|
|||
|
|
@ -1492,7 +1492,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
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
@ -155,7 +156,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,12 @@ 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, applyTitleFont);
|
||||
|
||||
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;
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@
|
|||
#include "tab_deck_editor_visual_tab_widget.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QByteArray>
|
||||
#include <QDebug>
|
||||
#include <QDockWidget>
|
||||
|
|
@ -261,17 +260,25 @@ void TabDeckEditorVisual::processMainboardCardClick(const QMouseEvent *event,
|
|||
}
|
||||
}
|
||||
|
||||
/** @brief Get a zone name corresponding to keyboard modifiers. */
|
||||
static QString zoneForClickModifiers(const Qt::KeyboardModifiers &modifiers)
|
||||
{
|
||||
if (modifiers.testFlag(Qt::ControlModifier)) {
|
||||
return DECK_ZONE_SIDE;
|
||||
} else if (modifiers.testFlag(Qt::ShiftModifier)) {
|
||||
return DECK_ZONE_MAYBEBOARD;
|
||||
} else {
|
||||
return DECK_ZONE_MAIN;
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Handles clicks on cards in the database display. */
|
||||
void TabDeckEditorVisual::processDatabaseCardClick(const QMouseEvent *event, const ExactCard &card)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
if (QApplication::keyboardModifiers() & Qt::ControlModifier) {
|
||||
addCard(card, DECK_ZONE_SIDE);
|
||||
} else {
|
||||
addCard(card, DECK_ZONE_MAIN);
|
||||
}
|
||||
addCard(card, zoneForClickModifiers(event->modifiers()));
|
||||
} else if (event->button() == Qt::RightButton) {
|
||||
decrementCard(card, DECK_ZONE_MAIN);
|
||||
decrementCard(card, zoneForClickModifiers(event->modifiers()));
|
||||
} else if (event->button() == Qt::MiddleButton) {
|
||||
deckDockWidget->actRemoveCard();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 "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>
|
||||
|
|
@ -65,8 +67,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>
|
||||
|
|
@ -117,8 +119,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);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
@page editing_decks Editing Decks
|
||||
|
||||
- @subpage editing_decks_classic
|
||||
- @subpage editing_decks_visual
|
||||
- @subpage editing_decks_classic
|
||||
- @subpage editing_decks_visual
|
||||
|
||||
- @subpage editing_decks_printings
|
||||
- @subpage visual_database_display
|
||||
- @subpage editing_decks_printings
|
||||
|
|
|
|||
|
|
@ -70,4 +70,4 @@ confirm.
|
|||
|
||||
The action will automatically import the deck from the online service without any other required user action.
|
||||
|
||||
Currently supported services are Archidekt, Deckstats, Moxfield, and TappedOut.
|
||||
Currently supported services are Archidekt, Deckstats, ManaBox, Moxfield, and TappedOut.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
@page visual_database_display Visual Database Display
|
||||
|
||||
# Purpose
|
||||
|
||||
The VisualDatabaseDisplay presents all the cards from the enabled sets in the CardDatabase, providing a visual way to find and add cards to your DeckList.
|
||||
|
||||
# Using the Visual Database Display
|
||||
|
||||
The VisualDatabaseDisplay can be opened by itself using the Tabs section in the menu bar at the top of the screen, or by selecting the "Visual Database Display" tab in the visual deck editor. When opened as a part of the visual deck editor, the VisualDatabaseDisplay can be used to add and remove cards from your deck. See @ref editing_decks_visual for more information about modifying your deck.
|
||||
|
||||
By default the cards are displayed as a grid of pictures. However, a table view using card names can be toggled by pressing the Visual/Table button at the top right of the widget.
|
||||
|
||||
# Filtering cards
|
||||
|
||||
The top section of the VisualDatabaseDisplay can be used to filter cards based on various card properties, as well as specifying in which way they should be sorted. Filters can be saved and reused at a later time by using the Save/Load button at the right of this panel.
|
||||
|
||||
# Modifying the Deck list
|
||||
|
||||
When the VisualDatabaseDisplay is opened as part of the visual deck editor, clicking on cards adds or removes them to and from your deck.
|
||||
|
||||
In the picture view, left-clicking on a card will add that card to the main board of your deck, while right-clicking will remove that printing of the card from the main board, if it exists. When clicking cards, modifier keys can be used to add (or remove) the card to zones other than the main board. Holding a Ctrl key on Windows and Linux or a Command key on MacOS adds/removes cards to the sideboard, while the Shift keys add/remove cards to the maybeboard.
|
||||
|
||||
In the table view, double-clicking on a card adds that card to the main board of your deck, while right-click opens the card menu. Holding the Ctrl key on Windows and Linux or the Command key on MacOS when double-clicking adds the card to the sideboard instead.
|
||||
|
||||
Tokens are always added to the token zone, regardless of which view is open or which modifier key is pressed.
|
||||
|
|
@ -83,7 +83,7 @@ LoadStatus CardDatabaseLoader::loadCardDatabase(const QString &path, CardDatabas
|
|||
auto startTime = QTime::currentTime();
|
||||
LoadStatus tempLoadStatus = NotLoaded;
|
||||
if (!path.isEmpty()) {
|
||||
QMutexLocker locker(loadFromFileMutex);
|
||||
QMutexLocker locker(&loadFromFileMutex);
|
||||
tempLoadStatus = loadFromFile(path, data);
|
||||
}
|
||||
|
||||
|
|
@ -102,7 +102,7 @@ LoadStatus CardDatabaseLoader::loadCardDatabases(bool ignoreCache)
|
|||
|
||||
LoadStatus CardDatabaseLoader::doLoadCardDatabases(bool ignoreCache)
|
||||
{
|
||||
QMutexLocker locker(reloadDatabaseMutex);
|
||||
QMutexLocker locker(&reloadDatabaseMutex);
|
||||
|
||||
if (!database) {
|
||||
qCWarning(CardDatabaseLoadingLog) << "Loader has no database pointer";
|
||||
|
|
|
|||
|
|
@ -177,8 +177,8 @@ private:
|
|||
ICardSetPriorityController *priorityController; /**< Controller for reconstructing set state. */
|
||||
QList<ICardDatabaseParser *> availableParsers; /**< List of available parsers for different formats. */
|
||||
|
||||
QBasicMutex *loadFromFileMutex = new QBasicMutex(); /**< Mutex for single-file loading. */
|
||||
QBasicMutex *reloadDatabaseMutex = new QBasicMutex(); /**< Mutex for reloading entire database. */
|
||||
QBasicMutex loadFromFileMutex; /**< Mutex for single-file loading. */
|
||||
QBasicMutex reloadDatabaseMutex; /**< Mutex for reloading entire database. */
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_CARD_DATABASE_LOADER_H
|
||||
|
|
|
|||
|
|
@ -423,8 +423,23 @@ DecklistCardNode *DeckList::addCard(const QString &cardName,
|
|||
const QString &cardProviderId,
|
||||
bool formatLegal)
|
||||
{
|
||||
auto node =
|
||||
tree.addCard(cardName, 1, zoneName, position, cardSetName, cardSetCollectorNumber, cardProviderId, formatLegal);
|
||||
return addCards(cardName, 1, zoneName, position, cardSetName, cardSetCollectorNumber, cardProviderId, formatLegal);
|
||||
}
|
||||
|
||||
DecklistCardNode *DeckList::addCards(const QString &cardName,
|
||||
int amount,
|
||||
const QString &zoneName,
|
||||
int position,
|
||||
const QString &cardSetName,
|
||||
const QString &cardSetCollectorNumber,
|
||||
const QString &cardProviderId,
|
||||
bool formatLegal)
|
||||
{
|
||||
if (amount <= 0) {
|
||||
return nullptr;
|
||||
}
|
||||
auto node = tree.addCard(cardName, amount, zoneName, position, cardSetName, cardSetCollectorNumber, cardProviderId,
|
||||
formatLegal);
|
||||
refreshDeckHash();
|
||||
return node;
|
||||
}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue