diff --git a/src/qt/forms/optionsdialog.ui b/src/qt/forms/optionsdialog.ui
index 99fb238772..7d8d8446aa 100644
--- a/src/qt/forms/optionsdialog.ui
+++ b/src/qt/forms/optionsdialog.ui
@@ -796,6 +796,41 @@
+ -
+
+
-
+
+
+ Font in QR Codes:
+
+
+ qrFont
+
+
+
+ -
+
+
+ -
+
+
+ 1NS17iag9jJgT…
+bc1p2q3rvn3gp…
+
+
+
+
+
+ -
+
+
+ Alternate the row colors for the "Peers" and "Banned peers" tables in the Peers tab.
+
+
+ Alternate row colors in the Peers tab
+
+
+
-
diff --git a/src/qt/optionsdialog.cpp b/src/qt/optionsdialog.cpp
index 4db2d6016c..6d9baf70df 100644
--- a/src/qt/optionsdialog.cpp
+++ b/src/qt/optionsdialog.cpp
@@ -206,6 +206,12 @@ OptionsDialog::OptionsDialog(QWidget* parent, bool enableWallet)
}
setupFontOptions(ui->moneyFont, ui->moneyFont_preview);
+ setupFontOptions(ui->qrFont, ui->qrFont_preview);
+#ifndef USE_QRCODE
+ ui->qrFontLabel->setVisible(false);
+ ui->qrFont->setVisible(false);
+ ui->qrFont_preview->setVisible(false);
+#endif
GUIUtil::handleCloseWindowShortcut(this);
}
@@ -246,6 +252,9 @@ void OptionsDialog::setModel(OptionsModel *_model)
const auto& font_for_money = _model->data(_model->index(OptionsModel::FontForMoney, 0), Qt::EditRole).value();
setFontChoice(ui->moneyFont, font_for_money);
+ const auto& font_for_qrcodes = _model->data(_model->index(OptionsModel::FontForQRCodes, 0), Qt::EditRole).value();
+ setFontChoice(ui->qrFont, font_for_qrcodes);
+
updateDefaultProxyNets();
}
@@ -320,6 +329,7 @@ void OptionsDialog::setMapper()
#endif
/* Display */
+ mapper->addMapping(ui->peersTabAlternatingRowColors, OptionsModel::PeersTabAlternatingRowColors);
mapper->addMapping(ui->lang, OptionsModel::Language);
mapper->addMapping(ui->unit, OptionsModel::DisplayUnit);
mapper->addMapping(ui->thirdPartyTxUrls, OptionsModel::ThirdPartyTxUrls);
@@ -385,6 +395,7 @@ void OptionsDialog::on_openBitcoinConfButton_clicked()
void OptionsDialog::on_okButton_clicked()
{
model->setData(model->index(OptionsModel::FontForMoney, 0), ui->moneyFont->itemData(ui->moneyFont->currentIndex()));
+ model->setData(model->index(OptionsModel::FontForQRCodes, 0), ui->qrFont->itemData(ui->qrFont->currentIndex()));
mapper->submit();
accept();
diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp
index 0c21c6748d..f213a15708 100644
--- a/src/qt/optionsmodel.cpp
+++ b/src/qt/optionsmodel.cpp
@@ -256,6 +256,17 @@ bool OptionsModel::Init(bilingual_str& error)
}
Q_EMIT fontForMoneyChanged(getFontForMoney());
+ if (settings.contains("FontForQRCodes")) {
+ m_font_qrcodes = FontChoiceFromString(settings.value("FontForQRCodes").toString());
+ }
+ Q_EMIT fontForQRCodesChanged(getFontChoiceForQRCodes());
+
+ if (!settings.contains("PeersTabAlternatingRowColors")) {
+ settings.setValue("PeersTabAlternatingRowColors", "false");
+ }
+ m_peers_tab_alternating_row_colors = settings.value("PeersTabAlternatingRowColors").toBool();
+ Q_EMIT peersTabAlternatingRowColorsChanged(m_peers_tab_alternating_row_colors);
+
m_mask_values = settings.value("mask_values", false).toBool();
return true;
@@ -465,6 +476,10 @@ QVariant OptionsModel::getOption(OptionID option, const std::string& suffix) con
return QString::fromStdString(SettingToString(setting(), ""));
case FontForMoney:
return QVariant::fromValue(m_font_money);
+ case FontForQRCodes:
+ return QVariant::fromValue(m_font_qrcodes);
+ case PeersTabAlternatingRowColors:
+ return m_peers_tab_alternating_row_colors;
case CoinControlFeatures:
return fCoinControlFeatures;
case EnablePSBTControls:
@@ -649,6 +664,20 @@ bool OptionsModel::setOption(OptionID option, const QVariant& value, const std::
Q_EMIT fontForMoneyChanged(getFontForMoney());
break;
}
+ case FontForQRCodes:
+ {
+ const auto& new_font = value.value();
+ if (m_font_qrcodes == new_font) break;
+ settings.setValue("FontForQRCodes", FontChoiceToString(new_font));
+ m_font_qrcodes = new_font;
+ Q_EMIT fontForQRCodesChanged(new_font);
+ break;
+ }
+ case PeersTabAlternatingRowColors:
+ m_peers_tab_alternating_row_colors = value.toBool();
+ settings.setValue("PeersTabAlternatingRowColors", m_peers_tab_alternating_row_colors);
+ Q_EMIT peersTabAlternatingRowColorsChanged(m_peers_tab_alternating_row_colors);
+ break;
case CoinControlFeatures:
fCoinControlFeatures = value.toBool();
settings.setValue("fCoinControlFeatures", fCoinControlFeatures);
diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h
index b5ea6c783e..e7048e4b2e 100644
--- a/src/qt/optionsmodel.h
+++ b/src/qt/optionsmodel.h
@@ -63,6 +63,8 @@ public:
ThirdPartyTxUrls, // QString
Language, // QString
FontForMoney, // FontChoice
+ FontForQRCodes, // FontChoice
+ PeersTabAlternatingRowColors, // bool
CoinControlFeatures, // bool
SubFeeFromAmount, // bool
ThreadsScriptVerif, // int
@@ -104,6 +106,8 @@ public:
BitcoinUnit getDisplayUnit() const { return m_display_bitcoin_unit; }
QString getThirdPartyTxUrls() const { return strThirdPartyTxUrls; }
QFont getFontForMoney() const;
+ FontChoice getFontChoiceForQRCodes() const { return m_font_qrcodes; }
+ bool getPeersTabAlternatingRowColors() const { return m_peers_tab_alternating_row_colors; }
bool getCoinControlFeatures() const { return fCoinControlFeatures; }
bool getSubFeeFromAmount() const { return m_sub_fee_from_amount; }
bool getEnablePSBTControls() const { return m_enable_psbt_controls; }
@@ -131,6 +135,8 @@ private:
BitcoinUnit m_display_bitcoin_unit;
QString strThirdPartyTxUrls;
FontChoice m_font_money{FontChoiceAbstract::EmbeddedFont};
+ FontChoice m_font_qrcodes{FontChoiceAbstract::EmbeddedFont};
+ bool m_peers_tab_alternating_row_colors;
bool fCoinControlFeatures;
bool m_sub_fee_from_amount;
bool m_enable_psbt_controls;
@@ -153,6 +159,8 @@ Q_SIGNALS:
void coinControlFeaturesChanged(bool);
void showTrayIconChanged(bool);
void fontForMoneyChanged(const QFont&);
+ void fontForQRCodesChanged(const FontChoice&);
+ void peersTabAlternatingRowColorsChanged(bool);
};
Q_DECLARE_METATYPE(OptionsModel::FontChoice)
diff --git a/src/qt/qrimagewidget.cpp b/src/qt/qrimagewidget.cpp
index f6e712a047..712e25cbf9 100644
--- a/src/qt/qrimagewidget.cpp
+++ b/src/qt/qrimagewidget.cpp
@@ -5,6 +5,7 @@
#include
#include
+#include
#include
#include
@@ -29,7 +30,7 @@ QRImageWidget::QRImageWidget(QWidget* parent)
contextMenu->addAction(tr("&Copy Image"), this, &QRImageWidget::copyImage);
}
-bool QRImageWidget::setQR(const QString& data, const QString& text)
+bool QRImageWidget::setQR(const QString& data, const QString& text, const OptionsModel::FontChoice& fontchoice)
{
#ifdef USE_QRCODE
setText("");
@@ -48,36 +49,71 @@ bool QRImageWidget::setQR(const QString& data, const QString& text)
return false;
}
- QImage qrImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32);
- qrImage.fill(0xffffff);
+ QImage qrImage = QImage(code->width, code->width, QImage::Format_RGB32);
unsigned char *p = code->data;
for (int y = 0; y < code->width; ++y) {
for (int x = 0; x < code->width; ++x) {
- qrImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff));
+ qrImage.setPixel(x, y, ((*p & 1) ? 0x0 : 0xffffff));
++p;
}
}
QRcode_free(code);
- const int qr_image_size = QR_IMAGE_SIZE + (text.isEmpty() ? 0 : 2 * QR_IMAGE_MARGIN);
- QImage qrAddrImage(qr_image_size, qr_image_size, QImage::Format_RGB32);
+ int qr_image_width = QR_IMAGE_SIZE + (2 * QR_IMAGE_MARGIN);
+ int qr_image_height = qr_image_width;
+ int qr_image_x_margin = QR_IMAGE_MARGIN;
+ int text_lines;
+ QFont font;
+ if (text.isEmpty()) {
+ text_lines = 0;
+ } else {
+ const int max_text_width = qr_image_width - (2 * QR_IMAGE_TEXT_MARGIN);
+
+ // Determine font to use
+ if (std::holds_alternative(fontchoice)) {
+ font = GUIUtil::fixedPitchFont(fontchoice != OptionsModel::UseBestSystemFont);
+ font.setWeight(QFont::Bold);
+ font.setStretch(QFont::SemiCondensed);
+ font.setLetterSpacing(QFont::AbsoluteSpacing, 1);
+
+ const qreal font_size = GUIUtil::calculateIdealFontSize(max_text_width, text, font);
+ font.setPointSizeF(font_size);
+ } else {
+ font = std::get(fontchoice);
+ }
+
+ // Plan how many lines are needed
+ QFontMetrics fm(font);
+ const int text_width = GUIUtil::TextWidth(fm, text);
+ if (text_width > max_text_width && text_width < max_text_width * 5 / 4) {
+ // Allow the image to grow up to 25% wider
+ qr_image_width = text_width + (2 * QR_IMAGE_TEXT_MARGIN);
+ qr_image_x_margin = (qr_image_width - QR_IMAGE_SIZE) / 2;
+ text_lines = 1;
+ } else {
+ text_lines = (text_width + max_text_width - 1) / max_text_width;
+ }
+ qr_image_height += (fm.height() * text_lines) + QR_IMAGE_TEXT_MARGIN;
+ }
+ QImage qrAddrImage(qr_image_width, qr_image_height, QImage::Format_RGB32);
qrAddrImage.fill(0xffffff);
{
QPainter painter(&qrAddrImage);
- painter.drawImage(QR_IMAGE_MARGIN, 0, qrImage.scaled(QR_IMAGE_SIZE, QR_IMAGE_SIZE));
+ painter.drawImage(qr_image_x_margin, QR_IMAGE_MARGIN, qrImage.scaled(QR_IMAGE_SIZE, QR_IMAGE_SIZE));
if (!text.isEmpty()) {
QRect paddedRect = qrAddrImage.rect();
- paddedRect.setHeight(QR_IMAGE_SIZE + QR_IMAGE_TEXT_MARGIN);
+ paddedRect.setHeight(paddedRect.height() - QR_IMAGE_TEXT_MARGIN);
- QFont font = GUIUtil::fixedPitchFont();
- font.setStretch(QFont::SemiCondensed);
- font.setLetterSpacing(QFont::AbsoluteSpacing, 1);
- const qreal font_size = GUIUtil::calculateIdealFontSize(paddedRect.width() - 2 * QR_IMAGE_TEXT_MARGIN, text, font);
- font.setPointSizeF(font_size);
+ QString text_wrapped = text;
+ const int char_per_line = (text.size() + text_lines - 1) / text_lines;
+ for (int line = 1, pos = 0; line < text_lines; ++line) {
+ pos += char_per_line;
+ text_wrapped.insert(pos, QChar{'\n'});
+ }
painter.setFont(font);
- painter.drawText(paddedRect, Qt::AlignBottom | Qt::AlignCenter, text);
+ painter.drawText(paddedRect, Qt::AlignBottom | Qt::AlignCenter, text_wrapped);
}
}
@@ -90,6 +126,11 @@ bool QRImageWidget::setQR(const QString& data, const QString& text)
#endif
}
+bool QRImageWidget::setQR(const QString& data)
+{
+ return setQR(data, "", OptionsModel::FontChoiceAbstract::EmbeddedFont);
+}
+
QImage QRImageWidget::exportImage()
{
return GUIUtil::GetImage(this);
diff --git a/src/qt/qrimagewidget.h b/src/qt/qrimagewidget.h
index d9ca2b899f..7f775cf146 100644
--- a/src/qt/qrimagewidget.h
+++ b/src/qt/qrimagewidget.h
@@ -5,6 +5,8 @@
#ifndef BITCOIN_QT_QRIMAGEWIDGET_H
#define BITCOIN_QT_QRIMAGEWIDGET_H
+#include
+
#include
#include
@@ -12,9 +14,9 @@
static const int MAX_URI_LENGTH = 255;
/* Size of exported QR Code image */
-static constexpr int QR_IMAGE_SIZE = 300;
-static constexpr int QR_IMAGE_TEXT_MARGIN = 10;
-static constexpr int QR_IMAGE_MARGIN = 2 * QR_IMAGE_TEXT_MARGIN;
+static constexpr int QR_IMAGE_SIZE = 252;
+static constexpr int QR_IMAGE_TEXT_MARGIN = 8;
+static constexpr int QR_IMAGE_MARGIN = 24;
QT_BEGIN_NAMESPACE
class QMenu;
@@ -29,7 +31,8 @@ class QRImageWidget : public QLabel
public:
explicit QRImageWidget(QWidget *parent = nullptr);
- bool setQR(const QString& data, const QString& text = "");
+ bool setQR(const QString& data);
+ bool setQR(const QString& data, const QString& text, const OptionsModel::FontChoice& fontchoice);
QImage exportImage();
public Q_SLOTS:
diff --git a/src/qt/receiverequestdialog.cpp b/src/qt/receiverequestdialog.cpp
index b4322ddc0f..53d225a6a2 100644
--- a/src/qt/receiverequestdialog.cpp
+++ b/src/qt/receiverequestdialog.cpp
@@ -47,8 +47,11 @@ void ReceiveRequestDialog::setInfo(const SendCoinsRecipient &_info)
QString uri = GUIUtil::formatBitcoinURI(info);
#ifdef USE_QRCODE
- if (ui->qr_code->setQR(uri, info.address)) {
+ if (ui->qr_code->setQR(uri, info.address, model->getOptionsModel()->getFontChoiceForQRCodes())) {
connect(ui->btnSaveAs, &QPushButton::clicked, ui->qr_code, &QRImageWidget::saveImage);
+ connect(model->getOptionsModel(), &OptionsModel::fontForQRCodesChanged, this, [&](const OptionsModel::FontChoice& fontchoice){
+ ui->qr_code->setQR(uri, info.address, fontchoice);
+ });
} else {
ui->btnSaveAs->setEnabled(false);
}
diff --git a/src/qt/rpcconsole.cpp b/src/qt/rpcconsole.cpp
index ae3f9aa686..c9b680ec13 100644
--- a/src/qt/rpcconsole.cpp
+++ b/src/qt/rpcconsole.cpp
@@ -14,6 +14,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -490,6 +491,7 @@ RPCConsole::RPCConsole(interfaces::Node& node, const PlatformStyle *_platformSty
m_peer_widget_header_state = settings.value("PeersTabPeerHeaderState").toByteArray();
m_banlist_widget_header_state = settings.value("PeersTabBanlistHeaderState").toByteArray();
+ m_alternating_row_colors = settings.value("PeersTabAlternatingRowColors").toBool();
constexpr QChar nonbreaking_hyphen(8209);
const std::vector CONNECTION_TYPE_DOC{
@@ -686,6 +688,11 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
connect(model, &ClientModel::mempoolSizeChanged, this, &RPCConsole::setMempoolSize);
+ connect(model->getOptionsModel(), &OptionsModel::peersTabAlternatingRowColorsChanged, [this](bool alternating_row_colors) {
+ ui->peerWidget->setAlternatingRowColors(alternating_row_colors);
+ ui->banlistWidget->setAlternatingRowColors(alternating_row_colors);
+ });
+
// set up peer table
ui->peerWidget->setModel(model->peerTableSortProxy());
ui->peerWidget->verticalHeader()->hide();
@@ -701,6 +708,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
ui->peerWidget->horizontalHeader()->setSectionResizeMode(PeerTableModel::Age, QHeaderView::ResizeToContents);
ui->peerWidget->horizontalHeader()->setStretchLastSection(true);
ui->peerWidget->setItemDelegateForColumn(PeerTableModel::NetNodeId, new PeerIdViewDelegate(this));
+ ui->peerWidget->setAlternatingRowColors(m_alternating_row_colors);
// create peer table context menu
peersTableContextMenu = new QMenu(this);
@@ -733,6 +741,7 @@ void RPCConsole::setClientModel(ClientModel *model, int bestblock_height, int64_
}
ui->banlistWidget->horizontalHeader()->setSectionResizeMode(BanTableModel::Address, QHeaderView::ResizeToContents);
ui->banlistWidget->horizontalHeader()->setStretchLastSection(true);
+ ui->banlistWidget->setAlternatingRowColors(m_alternating_row_colors);
// create ban table context menu
banTableContextMenu = new QMenu(this);
diff --git a/src/qt/rpcconsole.h b/src/qt/rpcconsole.h
index 4747e611d0..91b32bda4c 100644
--- a/src/qt/rpcconsole.h
+++ b/src/qt/rpcconsole.h
@@ -177,6 +177,7 @@ private:
bool m_is_executing{false};
QByteArray m_peer_widget_header_state;
QByteArray m_banlist_widget_header_state;
+ bool m_alternating_row_colors{false};
/** Update UI with latest network info from model. */
void updateNetworkState();