Skip to content

Commit

Permalink
Merge g537 via gui_bech32_errpos
Browse files Browse the repository at this point in the history
  • Loading branch information
luke-jr committed Feb 14, 2025
2 parents ceebf13 + 87f2141 commit 207834a
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 17 deletions.
24 changes: 17 additions & 7 deletions src/qt/bitcoinaddressvalidator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

#include <key_io.h>

#include <vector>

/* Base58 characters are:
"123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
Expand All @@ -20,10 +22,8 @@ BitcoinAddressEntryValidator::BitcoinAddressEntryValidator(QObject *parent) :
{
}

QValidator::State BitcoinAddressEntryValidator::validate(QString &input, int &pos) const
QValidator::State BitcoinAddressEntryValidator::validate(QString &input, std::vector<int>&error_locations) const
{
Q_UNUSED(pos);

// Empty address is "intermediate" input
if (input.isEmpty())
return QValidator::Intermediate;
Expand Down Expand Up @@ -73,23 +73,33 @@ QValidator::State BitcoinAddressEntryValidator::validate(QString &input, int &po
}
else
{
error_locations.push_back(idx);
state = QValidator::Invalid;
}
}

return state;
}

QValidator::State BitcoinAddressEntryValidator::validate(QString &input, int &pos) const
{
std::vector<int> error_locations;
const auto ret = validate(input, error_locations);
if (!error_locations.empty()) pos = error_locations.at(0);
return ret;
}

BitcoinAddressCheckValidator::BitcoinAddressCheckValidator(QObject *parent) :
QValidator(parent)
BitcoinAddressEntryValidator(parent)
{
}

QValidator::State BitcoinAddressCheckValidator::validate(QString &input, int &pos) const
QValidator::State BitcoinAddressCheckValidator::validate(QString &input, std::vector<int>&error_locations) const
{
Q_UNUSED(pos);
// Validate the passed Bitcoin address
if (IsValidDestinationString(input.toStdString())) {
std::string error_msg;
CTxDestination dest = DecodeDestination(input.toStdString(), error_msg, &error_locations);
if (IsValidDestination(dest)) {
return QValidator::Acceptable;
}

Expand Down
10 changes: 7 additions & 3 deletions src/qt/bitcoinaddressvalidator.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@

#include <QValidator>

#include <vector>

/** Base58 entry widget validator, checks for valid characters and
* removes some whitespace.
*/
Expand All @@ -17,19 +19,21 @@ class BitcoinAddressEntryValidator : public QValidator
public:
explicit BitcoinAddressEntryValidator(QObject *parent);

State validate(QString &input, int &pos) const override;
virtual State validate(QString &input, std::vector<int>&error_locations) const;
virtual State validate(QString &input, int &pos) const override;
};

/** Bitcoin address widget validator, checks for a valid bitcoin address.
*/
class BitcoinAddressCheckValidator : public QValidator
class BitcoinAddressCheckValidator : public BitcoinAddressEntryValidator
{
Q_OBJECT

public:
explicit BitcoinAddressCheckValidator(QObject *parent);

State validate(QString &input, int &pos) const override;
using BitcoinAddressEntryValidator::validate;
State validate(QString &input, std::vector<int>&error_locations) const override;
};

#endif // BITCOIN_QT_BITCOINADDRESSVALIDATOR_H
71 changes: 65 additions & 6 deletions src/qt/qvalidatedlineedit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,15 @@
#include <qt/bitcoinaddressvalidator.h>
#include <qt/guiconstants.h>

#include <cmath>

#include <QColor>
#include <QCoreApplication>
#include <QFont>
#include <QInputMethodEvent>
#include <QList>
#include <QTextCharFormat>

QValidatedLineEdit::QValidatedLineEdit(QWidget* parent)
: QLineEdit(parent)
{
Expand All @@ -24,15 +33,25 @@ void QValidatedLineEdit::setText(const QString& text)
checkValidity();
}

void QValidatedLineEdit::setValid(bool _valid, bool with_warning)
double ColourLuminosity(QColor c)
{
const auto Lr = std::pow(c.redF(), 2.2) * .2126;
const auto Lg = std::pow(c.greenF(), 2.2) * .7152;
const auto Lb = std::pow(c.blueF(), 2.2) * .0722;
return Lr + Lg + Lb;
}

void QValidatedLineEdit::setValid(bool _valid, bool with_warning, const std::vector<int>&error_locations)
{
if(_valid == this->valid)
if(_valid && this->valid)
{
if (with_warning == m_has_warning || !valid) {
if (with_warning == m_has_warning) {
return;
}
}

QList<QInputMethodEvent::Attribute> attributes;

if(_valid)
{
m_has_warning = with_warning;
Expand All @@ -45,7 +64,38 @@ void QValidatedLineEdit::setValid(bool _valid, bool with_warning)
else
{
setStyleSheet("QValidatedLineEdit { " STYLE_INVALID "}");
if (!error_locations.empty()) {
const QColor normal_text_colour = palette().color(foregroundRole());
const QColor bg_colour = palette().color(backgroundRole());
const bool dark_mode = ColourLuminosity(bg_colour) < .36;
QColor error_colour;
if (normal_text_colour.red() > normal_text_colour.green() && normal_text_colour.red() > normal_text_colour.blue()) {
// red is dominant, avoid fg red
if (bg_colour.red() > bg_colour.blue() && bg_colour.green() > bg_colour.blue()) {
// bg is yellowish, fallback to blues
error_colour = dark_mode ? Qt::cyan : Qt::blue;
} else {
error_colour = dark_mode ? Qt::yellow : Qt::darkYellow;
}
} else {
error_colour = dark_mode ? QColor(255, 159, 159) : Qt::red;
}

QTextCharFormat format;
format.setFontUnderline(true);
format.setUnderlineStyle(QTextCharFormat::SpellCheckUnderline);
format.setUnderlineColor(error_colour);
format.setForeground(error_colour);
format.setFontWeight(QFont::Bold);
for (auto error_pos : error_locations) {
attributes.append(QInputMethodEvent::Attribute(QInputMethodEvent::TextFormat, error_pos - cursorPosition(), /*length=*/ 1, format));
}
}
}

QInputMethodEvent event(QString(), attributes);
QCoreApplication::sendEvent(this, &event);

this->valid = _valid;
}

Expand Down Expand Up @@ -107,11 +157,20 @@ void QValidatedLineEdit::checkValidity()
if (checkValidator)
{
QString address = text();
int pos = 0;
if (checkValidator->validate(address, pos) == QValidator::Acceptable)
QValidator::State validation_result;
std::vector<int> error_locations;
const BitcoinAddressEntryValidator * const address_validator = dynamic_cast<const BitcoinAddressEntryValidator*>(checkValidator);
if (address_validator) {
validation_result = address_validator->validate(address, error_locations);
} else {
int pos = 0;
validation_result = checkValidator->validate(address, pos);
error_locations.push_back(pos);
}
if (validation_result == QValidator::Acceptable)
setValid(true, has_warning);
else
setValid(false);
setValid(/* valid= */ false, /* with_warning= */ false, error_locations);
}
}
else
Expand Down
2 changes: 1 addition & 1 deletion src/qt/qvalidatedlineedit.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class QValidatedLineEdit : public QLineEdit

public Q_SLOTS:
void setText(const QString&);
void setValid(bool valid, bool with_warning=false);
void setValid(bool valid, bool with_warning=false, const std::vector<int>&error_locations=std::vector<int>());
void setEnabled(bool enabled);

Q_SIGNALS:
Expand Down

0 comments on commit 207834a

Please sign in to comment.