Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/Makefile.qt.include
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,6 @@ BITCOIN_QT_H = \
qt/donutchart.h \
qt/editaddressdialog.h \
qt/guiconstants.h \
qt/guiutil_font.h \
qt/guiutil.h \
qt/informationwidget.h \
qt/initexecutor.h \
Expand Down
1 change: 0 additions & 1 deletion src/qt/addressbookpage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
#include <qt/csvmodelwriter.h>
#include <qt/editaddressdialog.h>
#include <qt/guiutil.h>
#include <qt/guiutil_font.h>
#include <qt/optionsmodel.h>
#include <qt/qrdialog.h>

Expand Down
1 change: 0 additions & 1 deletion src/qt/addresstablemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
#include <qt/addresstablemodel.h>

#include <qt/guiutil.h>
#include <qt/guiutil_font.h>
#include <qt/walletmodel.h>

#include <key_io.h>
Expand Down
122 changes: 85 additions & 37 deletions src/qt/appearancewidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,23 @@
#include <qt/forms/ui_appearancewidget.h>

#include <qt/appearancewidget.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>

#include <util/system.h>

#include <QComboBox>
#include <QDataWidgetMapper>
#include <QDialogButtonBox>
#include <QFontDialog>
#include <QFontInfo>
#include <QLabel>
#include <QSettings>
#include <QSlider>

#include <algorithm>
#include <cstdlib>

int setFontChoice(QComboBox* cb, const OptionsModel::FontChoice& fc)
{
int i;
Expand Down Expand Up @@ -76,19 +82,20 @@ AppearanceWidget::AppearanceWidget(QWidget* parent) :
QWidget(parent),
ui{new Ui::AppearanceWidget()},
prevTheme{GUIUtil::getActiveTheme()},
prevScale{GUIUtil::g_font_registry.GetFontScale()},
prevFontFamily{GUIUtil::g_font_registry.GetFont()},
prevWeightNormal{GUIUtil::g_font_registry.GetWeightNormal()},
prevWeightBold{GUIUtil::g_font_registry.GetWeightBold()}
prevScale{GUIUtil::fontScale()},
prevFontFamily{GUIUtil::activeFont()},
prevWeightNormalArg{GUIUtil::currentWeightArg(GUIUtil::FontWeight::Normal)},
prevWeightBoldArg{GUIUtil::currentWeightArg(GUIUtil::FontWeight::Bold)}
{
ui->setupUi(this);

for (const QString& entry : GUIUtil::listThemes()) {
ui->theme->addItem(entry, QVariant(entry));
}

for (size_t idx{0}; idx < GUIUtil::g_fonts_known.size(); idx++) {
const auto& [font, selectable] = GUIUtil::g_fonts_known[idx];
const auto& known = GUIUtil::knownFonts();
for (size_t idx{0}; idx < known.size(); idx++) {
const auto& [font, selectable] = known[idx];
if (selectable) { ui->fontFamily->addItem(font, QVariant((uint16_t)idx)); }
}

Expand Down Expand Up @@ -127,19 +134,19 @@ AppearanceWidget::~AppearanceWidget()
if (prevTheme != GUIUtil::getActiveTheme()) {
updateTheme(prevTheme);
}
if (prevFontFamily != GUIUtil::g_font_registry.GetFont()) {
const bool setfont_ret{GUIUtil::g_font_registry.SetFont(prevFontFamily)};
if (prevFontFamily != GUIUtil::activeFont()) {
const bool setfont_ret{GUIUtil::setActiveFont(prevFontFamily)};
assert(setfont_ret);
GUIUtil::setApplicationFont();
}
if (prevScale != GUIUtil::g_font_registry.GetFontScale()) {
GUIUtil::g_font_registry.SetFontScale(prevScale);
if (prevScale != GUIUtil::fontScale()) {
GUIUtil::setFontScale(prevScale);
}
if (prevWeightNormal != GUIUtil::g_font_registry.GetWeightNormal()) {
GUIUtil::g_font_registry.SetWeightNormal(prevWeightNormal);
if (prevWeightNormalArg != GUIUtil::currentWeightArg(GUIUtil::FontWeight::Normal)) {
GUIUtil::setWeightFromArg(GUIUtil::FontWeight::Normal, prevWeightNormalArg);
}
if (prevWeightBold != GUIUtil::g_font_registry.GetWeightBold()) {
GUIUtil::g_font_registry.SetWeightBold(prevWeightBold);
if (prevWeightBoldArg != GUIUtil::currentWeightArg(GUIUtil::FontWeight::Bold)) {
GUIUtil::setWeightFromArg(GUIUtil::FontWeight::Bold, prevWeightBoldArg);
}
// Restore monospace font if cancelled
if (model) {
Expand Down Expand Up @@ -180,32 +187,28 @@ void AppearanceWidget::setModel(OptionsModel* _model)
const bool override_family{_model->isOptionOverridden("-font-family")};
if (override_family) {
ui->fontFamily->setEnabled(false);
if (const auto idx{ui->fontFamily->findText(GUIUtil::g_font_registry.GetFont())}; idx != -1) {
if (const auto idx{ui->fontFamily->findText(GUIUtil::activeFont())}; idx != -1) {
ui->fontFamily->setCurrentIndex(idx);
}
}

if (_model->isOptionOverridden("-font-scale")) {
ui->fontScaleSlider->setEnabled(false);
ui->fontScaleSlider->setValue(GUIUtil::g_font_registry.GetFontScale());
ui->fontScaleSlider->setValue(GUIUtil::fontScale());
}

if (bool is_overridden{_model->isOptionOverridden("-font-weight-normal")}; is_overridden || override_family) {
if (is_overridden) {
ui->fontWeightNormalSlider->setEnabled(false);
}
if (const auto idx{GUIUtil::g_font_registry.WeightToIdx(GUIUtil::g_font_registry.GetWeightNormal())}; idx != -1) {
ui->fontWeightNormalSlider->setValue(idx);
}
ui->fontWeightNormalSlider->setValue(GUIUtil::currentWeightArg(GUIUtil::FontWeight::Normal));
}

if (bool is_overridden{_model->isOptionOverridden("-font-weight-bold")}; is_overridden || override_family) {
if (is_overridden) {
ui->fontWeightBoldSlider->setEnabled(false);
}
if (const auto idx{GUIUtil::g_font_registry.WeightToIdx(GUIUtil::g_font_registry.GetWeightBold())}; idx != -1) {
ui->fontWeightBoldSlider->setValue(idx);
}
ui->fontWeightBoldSlider->setValue(GUIUtil::currentWeightArg(GUIUtil::FontWeight::Bold));
}
}

Expand All @@ -229,7 +232,7 @@ void AppearanceWidget::updateTheme(const QString& theme)

void AppearanceWidget::updateFontFamily(int index)
{
const bool setfont_ret{GUIUtil::g_font_registry.SetFont(GUIUtil::g_fonts_known[ui->fontFamily->itemData(index).toInt()].first)};
const bool setfont_ret{GUIUtil::setActiveFont(GUIUtil::knownFonts()[ui->fontFamily->itemData(index).toInt()].first)};
assert(setfont_ret);
GUIUtil::setApplicationFont();
GUIUtil::updateFonts();
Expand All @@ -238,7 +241,7 @@ void AppearanceWidget::updateFontFamily(int index)

void AppearanceWidget::updateFontScale(int nScale)
{
GUIUtil::g_font_registry.SetFontScale(nScale);
GUIUtil::setFontScale(nScale);
GUIUtil::updateFonts();
}

Expand All @@ -248,9 +251,11 @@ void AppearanceWidget::updateFontWeightNormal(int nValue, bool fForce)
if (nValue > ui->fontWeightBoldSlider->value() && !fForce) {
nSliderValue = ui->fontWeightBoldSlider->value();
}
nSliderValue = std::ranges::min(GUIUtil::supportedWeightArgs(), {},
[nSliderValue](int x) { return std::abs(x - nSliderValue); });
const QSignalBlocker blocker(ui->fontWeightNormalSlider);
ui->fontWeightNormalSlider->setValue(nSliderValue);
GUIUtil::g_font_registry.SetWeightNormal(GUIUtil::g_font_registry.IdxToWeight(ui->fontWeightNormalSlider->value()));
GUIUtil::setWeightFromArg(GUIUtil::FontWeight::Normal, nSliderValue);
GUIUtil::setApplicationFont();
GUIUtil::updateFonts();
}
Expand All @@ -261,9 +266,11 @@ void AppearanceWidget::updateFontWeightBold(int nValue, bool fForce)
if (nValue < ui->fontWeightNormalSlider->value() && !fForce) {
nSliderValue = ui->fontWeightNormalSlider->value();
}
nSliderValue = std::ranges::min(GUIUtil::supportedWeightArgs(), {},
[nSliderValue](int x) { return std::abs(x - nSliderValue); });
const QSignalBlocker blocker(ui->fontWeightBoldSlider);
ui->fontWeightBoldSlider->setValue(nSliderValue);
GUIUtil::g_font_registry.SetWeightBold(GUIUtil::g_font_registry.IdxToWeight(ui->fontWeightBoldSlider->value()));
GUIUtil::setWeightFromArg(GUIUtil::FontWeight::Bold, nSliderValue);
GUIUtil::setApplicationFont();
GUIUtil::updateFonts();
}
Expand All @@ -283,19 +290,60 @@ void AppearanceWidget::updateMoneyFont(int index)

void AppearanceWidget::updateWeightSlider(const bool fForce)
{
int nMaximum = GUIUtil::g_font_registry.GetSupportedWeights().size() - 1;
const auto supported = GUIUtil::supportedWeightArgs();
const int nMin = supported.front();
const int nMax = supported.back();

ui->fontWeightNormalSlider->setMinimum(0);
ui->fontWeightNormalSlider->setMaximum(nMaximum);
ui->fontWeightNormalSlider->setMinimum(nMin);
ui->fontWeightNormalSlider->setMaximum(nMax);

ui->fontWeightBoldSlider->setMinimum(0);
ui->fontWeightBoldSlider->setMaximum(nMaximum);
ui->fontWeightBoldSlider->setMinimum(nMin);
ui->fontWeightBoldSlider->setMaximum(nMax);
Comment on lines +297 to +301

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Limit weight sliders to valid supported weights

updateWeightSlider() now sets each slider to a continuous [min,max] range from supportedWeightArgs(), but supported weights are often sparse (for example, a font may support only a subset like 3 and 6). That lets users pick intermediate values that are unsupported; updateFontWeightNormal/Bold() then calls setWeightFromArg(...) and silently ignores failure, so the UI value can diverge from the applied font and an invalid weight can be persisted. Previously the slider operated on dense indices over only supported weights, so this regression is new.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restrict weight slider to supported discrete values

updateWeightSlider() now maps sliders to a continuous [min,max] argument range, but many fonts expose only a sparse subset of supported weight args. In that case users can select in-between values that setWeightFromArg(...) rejects, and updateFontWeightNormal/Bold() ignore that failure and still keep the slider at the rejected value. This leaves the UI and persisted setting out of sync with the actual applied font weight after changing fonts or moving the slider.

Useful? React with 👍 / 👎.


if (fForce || !GUIUtil::g_font_registry.IsValidWeight(prevWeightNormal) || !GUIUtil::g_font_registry.IsValidWeight(prevWeightBold)) {
int nIndexNormal = GUIUtil::g_font_registry.WeightToIdx(GUIUtil::g_font_registry.GetWeightNormalDefault());
int nIndexBold = GUIUtil::g_font_registry.WeightToIdx(GUIUtil::g_font_registry.GetWeightBoldDefault());
assert(nIndexNormal != -1 && nIndexBold != -1);
updateFontWeightNormal(nIndexNormal, true);
updateFontWeightBold(nIndexBold, true);
if (fForce) {
updateFontWeightNormal(GUIUtil::defaultWeightArg(GUIUtil::FontWeight::Normal), true);
updateFontWeightBold(GUIUtil::defaultWeightArg(GUIUtil::FontWeight::Bold), true);
Comment on lines +303 to +305

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Don't wipe a font family's cached weights when switching families.

src/qt/guiutil_font.cpp now keeps bold/normal selections per family in FontRegistry::m_weights, but Lines 304-305 immediately replace the newly selected family's cached values with defaultWeightArg(...). That means just previewing another family silently loses any previously chosen weights for that family before the user touches either slider. Initialize the sliders from currentWeightArg(...) for the active family instead.

Suggested fix
-    if (fForce) {
-        updateFontWeightNormal(GUIUtil::defaultWeightArg(GUIUtil::FontWeight::Normal), true);
-        updateFontWeightBold(GUIUtil::defaultWeightArg(GUIUtil::FontWeight::Bold), true);
-    }
+    if (fForce) {
+        updateFontWeightNormal(GUIUtil::currentWeightArg(GUIUtil::FontWeight::Normal), true);
+        updateFontWeightBold(GUIUtil::currentWeightArg(GUIUtil::FontWeight::Bold), true);
+    }
Based on learnings, refactoring PRs in this repo should avoid behavior changes and keep structural changes separate from follow-up UX changes.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/qt/appearancewidget.cpp` around lines 303 - 305, The current code in the
fForce branch calls updateFontWeightNormal(...) and updateFontWeightBold(...)
with GUIUtil::defaultWeightArg(...), which overwrites the selected family's
cached weights in FontRegistry::m_weights; change this to initialize the sliders
from the active family's stored values by calling GUIUtil::currentWeightArg(...)
(or equivalent accessor that reads FontRegistry::m_weights for the current
family) and pass those results into updateFontWeightNormal(...) and
updateFontWeightBold(...), so previewing a different family does not wipe its
saved bold/normal selections.

}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

void AppearanceWidget::setupAppearance(QWidget* parent, OptionsModel* model)
{
if (!QSettings().value("fAppearanceSetupDone", false).toBool()) {
// Create the dialog
QDialog dlg(parent);
dlg.setObjectName("AppearanceSetup");
dlg.setWindowTitle(QObject::tr("Appearance Setup"));
dlg.setWindowIcon(QIcon(":icons/dash"));
// And the widgets we add to it
QLabel lblHeading(QObject::tr("Please choose your preferred settings for the appearance of %1").arg(PACKAGE_NAME), &dlg);
lblHeading.setObjectName("lblHeading");
lblHeading.setWordWrap(true);
QLabel lblSubHeading(QObject::tr("This can also be adjusted later in the \"Appearance\" tab of the preferences."), &dlg);
lblSubHeading.setObjectName("lblSubHeading");
lblSubHeading.setWordWrap(true);
AppearanceWidget appearance(&dlg);
appearance.setModel(model);
QFrame line(&dlg);
line.setFrameShape(QFrame::HLine);
QDialogButtonBox buttonBox(QDialogButtonBox::Save);
// Put them into a vbox and add the vbox to the dialog
QVBoxLayout layout;
layout.addWidget(&lblHeading);
layout.addWidget(&lblSubHeading);
layout.addWidget(&line);
layout.addWidget(&appearance);
layout.addWidget(&buttonBox);
dlg.setLayout(&layout);
// Adjust the headings
GUIUtil::setFont({&lblHeading}, GUIUtil::FontWeight::Bold, 16);
GUIUtil::setFont({&lblSubHeading}, GUIUtil::FontWeight::Normal, 14, true);
// Make sure the dialog closes and accepts the settings if save has been pressed
QObject::connect(&buttonBox, &QDialogButtonBox::accepted, [&]() {
QSettings().setValue("fAppearanceSetupDone", true);
appearance.accept();
dlg.accept();
});
// And fire it!
dlg.exec();
Comment on lines +337 to +347

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Apply the heading styles before showing the dialog.

GUIUtil::setFont() only queues the update. Without an GUIUtil::updateFonts() pass here, these labels keep their default styling unless some unrelated font/theme refresh happens while the dialog is open.

Suggested fix
         // Adjust the headings
         GUIUtil::setFont({&lblHeading}, GUIUtil::FontWeight::Bold, 16);
         GUIUtil::setFont({&lblSubHeading}, GUIUtil::FontWeight::Normal, 14, true);
+        GUIUtil::updateFonts();
         // Make sure the dialog closes and accepts the settings if save has been pressed
         QObject::connect(&buttonBox, &QDialogButtonBox::accepted, [&]() {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/qt/appearancewidget.cpp` around lines 330 - 340, The heading font changes
are only queued by GUIUtil::setFont for lblHeading and lblSubHeading and won't
apply immediately; after calling GUIUtil::setFont(...) for those labels, call
GUIUtil::updateFonts() before showing the dialog (i.e., before dlg.exec()) so
the queued font updates are applied; ensure you keep the existing
QObject::connect and dlg.exec() calls and only insert the GUIUtil::updateFonts()
call after the setFont calls and before dlg.exec().

}
}
12 changes: 8 additions & 4 deletions src/qt/appearancewidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@

#include <QWidget>

#include <qt/guiutil.h>
#include <qt/guiutil_font.h>
#include <qt/optionsmodel.h>

namespace Ui {
Expand Down Expand Up @@ -51,11 +49,17 @@ private Q_SLOTS:
QString prevTheme;
int prevScale;
QString prevFontFamily;
QFont::Weight prevWeightNormal;
QFont::Weight prevWeightBold;
//! Snapshots stored as -font-weight-* arg ints (0..8), matching slider values.
int prevWeightNormalArg;
int prevWeightBoldArg;
OptionsModel::FontChoice prevMoneyFont{OptionsModel::FontChoiceAbstract::ApplicationFont};

void updateWeightSlider(bool fForce = false);

public:
// Setup appearance settings if not done yet
static void setupAppearance(QWidget* parent, OptionsModel* model);

};

#endif // BITCOIN_QT_APPEARANCEWIDGET_H
3 changes: 1 addition & 2 deletions src/qt/askpassphrasedialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@

#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <qt/guiutil_font.h>
#include <qt/walletmodel.h>

#include <support/allocators/secure.h>
Expand All @@ -29,7 +28,7 @@ AskPassphraseDialog::AskPassphraseDialog(Mode _mode, QWidget *parent, SecureStri
{
ui->setupUi(this);

GUIUtil::setFont({ui->capsLabel}, {GUIUtil::FontWeight::Bold});
GUIUtil::setFont({ui->capsLabel}, GUIUtil::FontWeight::Bold);

GUIUtil::updateFonts();

Expand Down
Loading
Loading