mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 01:23:24 -08:00
[Fonts] Add per-purpose font section to palette editor (#7536)
* [Fonts] Add per-purpose font section to palette editor * [Fonts] Make the editor's fallback and Reset preview-independent - Add ThemeManager::defaultAppFont(), which resolves an unset role against the startup font instead of currentFonts, and use it in FontGridWidget::loadFonts so the grid never shows the live preview as the theme's default. - Reload the live theme in PaletteEditorDialog::onReset before re-reading the grid, so Reset restores the saved fonts before loadFonts resolves fallbacks. --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
54797452da
commit
634f8115a5
7 changed files with 317 additions and 10 deletions
|
|
@ -154,6 +154,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/palette_editor/palette_generator.cpp
|
src/interface/palette_editor/palette_generator.cpp
|
||||||
src/interface/palette_editor/quick_setup_panel.cpp
|
src/interface/palette_editor/quick_setup_panel.cpp
|
||||||
src/interface/palette_editor/palette_grid_widget.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/palette_editor/palette_editor_dialog.cpp
|
||||||
src/interface/widgets/cards/additional_info/color_identity_widget.cpp
|
src/interface/widgets/cards/additional_info/color_identity_widget.cpp
|
||||||
src/interface/widgets/cards/additional_info/deck_color_identity.cpp
|
src/interface/widgets/cards/additional_info/deck_color_identity.cpp
|
||||||
|
|
|
||||||
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_config.h"
|
||||||
#include "../theme_manager.h"
|
#include "../theme_manager.h"
|
||||||
|
#include "font_grid_widget.h"
|
||||||
#include "palette_generator.h"
|
#include "palette_generator.h"
|
||||||
#include "palette_grid_widget.h"
|
#include "palette_grid_widget.h"
|
||||||
#include "quick_setup_panel.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
|
// Load both scheme configs upfront so switching is instant
|
||||||
loadSchemes();
|
loadSchemes();
|
||||||
|
loadFonts();
|
||||||
|
|
||||||
loadedScheme = themeManager->isDarkMode(themeDirPath) ? "Dark" : "Light";
|
loadedScheme = themeManager->isDarkMode(themeDirPath) ? "Dark" : "Light";
|
||||||
|
|
||||||
|
|
@ -125,6 +127,32 @@ void PaletteEditorDialog::setupUi()
|
||||||
paletteGrid->setVisible(false);
|
paletteGrid->setVisible(false);
|
||||||
root->addWidget(paletteGrid, 1);
|
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
|
// Footer
|
||||||
root->addWidget(makeSeparator());
|
root->addWidget(makeSeparator());
|
||||||
footer = new QWidget;
|
footer = new QWidget;
|
||||||
|
|
@ -157,6 +185,7 @@ void PaletteEditorDialog::setupUi()
|
||||||
connect(autoApplyTimer, &QTimer::timeout, this, &PaletteEditorDialog::onApply);
|
connect(autoApplyTimer, &QTimer::timeout, this, &PaletteEditorDialog::onApply);
|
||||||
connect(quickSetupPanel, &QuickSetupPanel::valueChanged, this, &PaletteEditorDialog::onGenerateFromAccent);
|
connect(quickSetupPanel, &QuickSetupPanel::valueChanged, this, &PaletteEditorDialog::onGenerateFromAccent);
|
||||||
connect(paletteGrid, &PaletteGridWidget::paletteChanged, this, [this] { autoApplyTimer->start(); });
|
connect(paletteGrid, &PaletteGridWidget::paletteChanged, this, [this] { autoApplyTimer->start(); });
|
||||||
|
connect(fontGrid, &FontGridWidget::fontsChanged, this, [this] { autoApplyTimer->start(); });
|
||||||
connect(revertButton, &QPushButton::clicked, this, &PaletteEditorDialog::onRevertToDefault);
|
connect(revertButton, &QPushButton::clicked, this, &PaletteEditorDialog::onRevertToDefault);
|
||||||
connect(resetBtn, &QPushButton::clicked, this, &PaletteEditorDialog::onReset);
|
connect(resetBtn, &QPushButton::clicked, this, &PaletteEditorDialog::onReset);
|
||||||
connect(saveBtn, &QPushButton::clicked, this, &PaletteEditorDialog::onSave);
|
connect(saveBtn, &QPushButton::clicked, this, &PaletteEditorDialog::onSave);
|
||||||
|
|
@ -166,15 +195,32 @@ void PaletteEditorDialog::setupUi()
|
||||||
paletteGridToggleButton->setText(open ? tr("▼ Edit Palette") : tr("▶ Edit Palette"));
|
paletteGridToggleButton->setText(open ? tr("▼ Edit Palette") : tr("▶ Edit Palette"));
|
||||||
paletteGridSeparator->setVisible(open);
|
paletteGridSeparator->setVisible(open);
|
||||||
paletteGrid->setVisible(open);
|
paletteGrid->setVisible(open);
|
||||||
|
updateAdvancedHeight();
|
||||||
if (open) {
|
|
||||||
setMinimumHeight(680);
|
|
||||||
resize(width(), 680);
|
|
||||||
} else {
|
|
||||||
setMinimumHeight(220);
|
|
||||||
adjustSize(); // shrinks to fit just the visible content
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
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()
|
void PaletteEditorDialog::retranslateUi()
|
||||||
|
|
@ -189,12 +235,16 @@ void PaletteEditorDialog::retranslateUi()
|
||||||
editingLabel->setText(tr("Editing:"));
|
editingLabel->setText(tr("Editing:"));
|
||||||
paletteGridToggleButton->setText(tr("▶ Edit Palette"));
|
paletteGridToggleButton->setText(tr("▶ Edit Palette"));
|
||||||
paletteGridToggleButton->setToolTip(tr("Show or hide the per-role colour grid for manual tweaks"));
|
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"));
|
revertButton->setText(tr("↺ Revert to theme default"));
|
||||||
|
|
||||||
resetBtn->setText(tr("Reset"));
|
resetBtn->setText(tr("Reset"));
|
||||||
saveBtn->setText(tr("Save"));
|
saveBtn->setText(tr("Save"));
|
||||||
resetBtn->setToolTip(tr("Discard unsaved edits and restore the last saved palette"));
|
resetBtn->setToolTip(tr("Discard unsaved edits and restore the last saved palette and fonts"));
|
||||||
saveBtn->setToolTip(tr("Write palette-%1.toml and reload the theme").arg(loadedScheme.toLower()));
|
saveBtn->setToolTip(tr("Write palette-%1.toml and fonts.toml, then reload the theme").arg(loadedScheme.toLower()));
|
||||||
|
|
||||||
if (saveDir.isEmpty() || !ThemeManager::isDirReallyWritable(saveDir)) {
|
if (saveDir.isEmpty() || !ThemeManager::isDirReallyWritable(saveDir)) {
|
||||||
saveBtn->setEnabled(false);
|
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)
|
void PaletteEditorDialog::seedAccentFromScheme(const QString &scheme)
|
||||||
{
|
{
|
||||||
QColor seed = workingConfig.value(scheme).colors.value(QPalette::Active).value(QPalette::Highlight);
|
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()
|
void PaletteEditorDialog::onApply()
|
||||||
{
|
{
|
||||||
themeManager->previewPalette(paletteGrid->currentPaletteConfig(), loadedScheme);
|
themeManager->previewPalette(paletteGrid->currentPaletteConfig(), loadedScheme);
|
||||||
|
themeManager->previewFonts(fontGrid->currentFontConfig());
|
||||||
}
|
}
|
||||||
|
|
||||||
void PaletteEditorDialog::onSave()
|
void PaletteEditorDialog::onSave()
|
||||||
|
|
@ -308,6 +372,17 @@ void PaletteEditorDialog::onSave()
|
||||||
savedConfig[it.key()] = it.value();
|
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();
|
themeManager->reloadCurrentTheme();
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
|
@ -316,6 +391,11 @@ void PaletteEditorDialog::onReset()
|
||||||
{
|
{
|
||||||
workingConfig[loadedScheme] = savedConfig[loadedScheme];
|
workingConfig[loadedScheme] = savedConfig[loadedScheme];
|
||||||
paletteGrid->loadPalette(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);
|
seedAccentFromScheme(loadedScheme);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -350,6 +430,18 @@ void PaletteEditorDialog::onRevertToDefault()
|
||||||
workingConfig[loadedScheme] = def;
|
workingConfig[loadedScheme] = def;
|
||||||
paletteGrid->loadPalette(def);
|
paletteGrid->loadPalette(def);
|
||||||
seedAccentFromScheme(loadedScheme);
|
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)
|
void PaletteEditorDialog::changeEvent(QEvent *e)
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ class QComboBox;
|
||||||
class QDialogButtonBox;
|
class QDialogButtonBox;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
class PaletteGridWidget;
|
class PaletteGridWidget;
|
||||||
|
class FontGridWidget;
|
||||||
class QuickSetupPanel;
|
class QuickSetupPanel;
|
||||||
class QFrame;
|
class QFrame;
|
||||||
class QWidget;
|
class QWidget;
|
||||||
|
|
@ -38,8 +39,10 @@ private:
|
||||||
void setupUi();
|
void setupUi();
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
void refreshChromePalettes();
|
void refreshChromePalettes();
|
||||||
|
void updateAdvancedHeight();
|
||||||
void loadScheme(const QString &scheme); // snapshot current, switch, load
|
void loadScheme(const QString &scheme); // snapshot current, switch, load
|
||||||
void seedAccentFromScheme(const QString &scheme);
|
void seedAccentFromScheme(const QString &scheme);
|
||||||
|
void loadFonts(); // shared per theme, not split by light/dark
|
||||||
|
|
||||||
// Sub-widgets
|
// Sub-widgets
|
||||||
QWidget *header;
|
QWidget *header;
|
||||||
|
|
@ -49,6 +52,11 @@ private:
|
||||||
PaletteGridWidget *paletteGrid = nullptr;
|
PaletteGridWidget *paletteGrid = nullptr;
|
||||||
QPushButton *paletteGridToggleButton = nullptr;
|
QPushButton *paletteGridToggleButton = nullptr;
|
||||||
QFrame *paletteGridSeparator = nullptr;
|
QFrame *paletteGridSeparator = nullptr;
|
||||||
|
FontGridWidget *fontGrid = nullptr;
|
||||||
|
QPushButton *fontToggleButton = nullptr;
|
||||||
|
QFrame *fontSeparator = nullptr;
|
||||||
|
QWidget *fontSection = nullptr;
|
||||||
|
QLabel *fontNoteLabel = nullptr;
|
||||||
QWidget *footer;
|
QWidget *footer;
|
||||||
QComboBox *schemeComboBox = nullptr;
|
QComboBox *schemeComboBox = nullptr;
|
||||||
QDialogButtonBox *buttonBox = nullptr;
|
QDialogButtonBox *buttonBox = nullptr;
|
||||||
|
|
@ -68,6 +76,10 @@ private:
|
||||||
QMap<QString, PaletteConfig> workingConfig;
|
QMap<QString, PaletteConfig> workingConfig;
|
||||||
QMap<QString, PaletteConfig> savedConfig;
|
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;
|
QTimer *autoApplyTimer = nullptr;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
||||||
|
|
@ -450,6 +450,18 @@ FontConfig ThemeManager::loadFontConfig(const QString &themeDirPath)
|
||||||
return FontConfig::fromThemeDir(themeDirPath);
|
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)
|
bool ThemeManager::saveFontConfig(const QString &themeDirPath, const FontConfig &cfg)
|
||||||
{
|
{
|
||||||
if (themeDirPath.isEmpty()) {
|
if (themeDirPath.isEmpty()) {
|
||||||
|
|
@ -651,6 +663,14 @@ QFont ThemeManager::appFont(AppFont::Role role) const
|
||||||
return qApp->font();
|
return qApp->font();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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()
|
void ThemeManager::themeChangedSlot()
|
||||||
{
|
{
|
||||||
QString themeName = SettingsCache::instance().getThemeName();
|
QString themeName = SettingsCache::instance().getThemeName();
|
||||||
|
|
@ -717,6 +737,10 @@ void ThemeManager::themeChangedSlot()
|
||||||
const auto fontIt = currentFonts.fonts.constFind(AppFont::InterfaceDefault);
|
const auto fontIt = currentFonts.fonts.constFind(AppFont::InterfaceDefault);
|
||||||
if (fontIt != currentFonts.fonts.constEnd()) {
|
if (fontIt != currentFonts.fonts.constEnd()) {
|
||||||
qApp->setFont(fontIt.value());
|
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();
|
emit fontsChanged();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -132,6 +132,9 @@ public:
|
||||||
// theme directory when it is absent from the resolved (user) directory.
|
// theme directory when it is absent from the resolved (user) directory.
|
||||||
static PaletteConfig
|
static PaletteConfig
|
||||||
loadDefaultPaletteConfig(const QString &themeDirPath, const QString &themeName, const QString &colorScheme);
|
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
|
/** @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
|
* 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. */
|
* and FirstRunWizard's theme step so the two "generate + keep" paths can't drift. */
|
||||||
|
|
@ -149,6 +152,11 @@ public:
|
||||||
/** @brief Resolves an application font role: the theme's stored [Fonts]
|
/** @brief Resolves an application font role: the theme's stored [Fonts]
|
||||||
* value when present, otherwise the application font. */
|
* value when present, otherwise the application font. */
|
||||||
QFont appFont(AppFont::Role role) const;
|
QFont appFont(AppFont::Role role) 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 &getBgBrush(Role zone);
|
||||||
QBrush getExtraBgBrush(Role zone, int zoneId = 0);
|
QBrush getExtraBgBrush(Role zone, int zoneId = 0);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue