From 49ed0dc57ea7f5692c71ee08b33409b6c590f574 Mon Sep 17 00:00:00 2001 From: xdustinface Date: Tue, 16 Jun 2020 16:25:18 +0200 Subject: [PATCH 1/6] qt: Remove min-width of BitcoinAmountField in ReceiveCoinsDialog --- src/qt/forms/receivecoinsdialog.ui | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui index fa6c1f182250..821e0182aacb 100644 --- a/src/qt/forms/receivecoinsdialog.ui +++ b/src/qt/forms/receivecoinsdialog.ui @@ -99,12 +99,6 @@ - - - 80 - 0 - - An optional amount to request. Leave this empty or zero to not request a specific amount. @@ -291,8 +285,6 @@ showRequestButton removeRequestButton - - - + From 8924d31d4a786e9da6f89b078bdd90dbcdfa4d2a Mon Sep 17 00:00:00 2001 From: xdustinface Date: Wed, 17 Jun 2020 01:06:57 +0200 Subject: [PATCH 2/6] qt: Add BitcoinUnits::data(const int &row, int role) Make its data also accessible int, not only by QModelIndex. --- src/qt/bitcoinunits.cpp | 6 +++++- src/qt/bitcoinunits.h | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/qt/bitcoinunits.cpp b/src/qt/bitcoinunits.cpp index 54607806f1a9..b6c9e2fc57b6 100644 --- a/src/qt/bitcoinunits.cpp +++ b/src/qt/bitcoinunits.cpp @@ -246,7 +246,11 @@ int BitcoinUnits::rowCount(const QModelIndex &parent) const QVariant BitcoinUnits::data(const QModelIndex &index, int role) const { - int row = index.row(); + return data(index.row(), role); +} + +QVariant BitcoinUnits::data(const int &row, int role) const +{ if(row >= 0 && row < unitlist.size()) { Unit unit = unitlist.at(row); diff --git a/src/qt/bitcoinunits.h b/src/qt/bitcoinunits.h index cc16cacc0229..54d132d98db5 100644 --- a/src/qt/bitcoinunits.h +++ b/src/qt/bitcoinunits.h @@ -111,6 +111,7 @@ class BitcoinUnits: public QAbstractListModel }; int rowCount(const QModelIndex &parent) const; QVariant data(const QModelIndex &index, int role) const; + QVariant data(const int &row, int role) const; ///@} static QString removeSpaces(QString text) From 68f097b53d354cc5c5047d7b78e3c7645c6cd128 Mon Sep 17 00:00:00 2001 From: xdustinface Date: Mon, 15 Jun 2020 12:41:07 +0200 Subject: [PATCH 3/6] qt: Adjust BitcoinAmountField - AmountSpinBox (QAbstractBox) is now called AmountLineEdit (QLineEdit) - Replaced the AmountSpinBox and the QValueComboBox with just an AmountLineEdit - Adjusted min-size hint calculation - Increased maximum width - Right-Align text - Removed obsolete code --- src/qt/bitcoinamountfield.cpp | 215 ++++++++++++++-------------------- src/qt/bitcoinamountfield.h | 13 +- 2 files changed, 90 insertions(+), 138 deletions(-) diff --git a/src/qt/bitcoinamountfield.cpp b/src/qt/bitcoinamountfield.cpp index ac90a519df18..d04594c92d6e 100644 --- a/src/qt/bitcoinamountfield.cpp +++ b/src/qt/bitcoinamountfield.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include @@ -14,71 +13,98 @@ #include #include -/** QSpinBox that uses fixed-point numbers internally and uses our own - * formatting/parsing functions. +/** + * Parse a string into a number of base monetary units and + * return validity. + * @note Must return 0 if !valid. */ -class AmountSpinBox: public QAbstractSpinBox +static CAmount parse(const QString &text, int nUnit, bool *valid_out=0) { - Q_OBJECT - -public: - explicit AmountSpinBox(QWidget *parent): - QAbstractSpinBox(parent), - currentUnit(BitcoinUnits::DASH), - singleStep(100000) // satoshis + CAmount val = 0; + bool valid = BitcoinUnits::parse(nUnit, text, &val); + if(valid) { - setAlignment(Qt::AlignRight); - - connect(lineEdit(), SIGNAL(textEdited(QString)), this, SIGNAL(valueChanged())); + if(val < 0 || val > BitcoinUnits::maxMoney()) + valid = false; } + if(valid_out) + *valid_out = valid; + return valid ? val : 0; +} + +/** Amount widget validator, checks for valid CAmount value. + */ +class AmountValidator : public QValidator +{ + Q_OBJECT + int currentUnit; +public: + explicit AmountValidator(QObject *parent) : + QValidator(parent), + currentUnit(BitcoinUnits::DASH) {} - QValidator::State validate(QString &text, int &pos) const + State validate(QString &input, int &pos) const { - if(text.isEmpty()) + if(input.isEmpty()) return QValidator::Intermediate; bool valid = false; - parse(text, &valid); + parse(input, currentUnit, &valid); /* Make sure we return Intermediate so that fixup() is called on defocus */ return valid ? QValidator::Intermediate : QValidator::Invalid; } - void fixup(QString &input) const + void updateUnit(int nUnit) + { + currentUnit = nUnit; + } +}; + +/** QLineEdit that uses fixed-point numbers internally and uses our own + * formatting/parsing functions. + */ +class AmountLineEdit: public QLineEdit +{ + Q_OBJECT + AmountValidator* amountValidator; +public: + explicit AmountLineEdit(QWidget *parent): + QLineEdit(parent), + currentUnit(BitcoinUnits::DASH) + { + setAlignment(Qt::AlignLeft); + amountValidator = new AmountValidator(this); + setValidator(amountValidator); + connect(this, SIGNAL(textEdited(QString)), this, SIGNAL(valueChanged())); + } + + void fixup(const QString &input) { bool valid = false; - CAmount val = parse(input, &valid); + CAmount val = parse(input, currentUnit, &valid); if(valid) { - input = BitcoinUnits::format(currentUnit, val, false, BitcoinUnits::separatorAlways); - lineEdit()->setText(input); + setText(BitcoinUnits::format(currentUnit, val, false, BitcoinUnits::separatorAlways)); } } CAmount value(bool *valid_out=0) const { - return parse(text(), valid_out); + return parse(text(), currentUnit, valid_out); } void setValue(const CAmount& value) { - lineEdit()->setText(BitcoinUnits::format(currentUnit, value, false, BitcoinUnits::separatorAlways)); + setText(BitcoinUnits::format(currentUnit, value, false, BitcoinUnits::separatorAlways)); Q_EMIT valueChanged(); } - void stepBy(int steps) - { - bool valid = false; - CAmount val = value(&valid); - val = val + steps * singleStep; - val = qMin(qMax(val, CAmount(0)), BitcoinUnits::maxMoney()); - setValue(val); - } - void setDisplayUnit(int unit) { bool valid = false; CAmount val = value(&valid); currentUnit = unit; + amountValidator->updateUnit(unit); if(valid) setValue(val); @@ -86,67 +112,19 @@ class AmountSpinBox: public QAbstractSpinBox clear(); } - void setSingleStep(const CAmount& step) - { - singleStep = step; - } - QSize minimumSizeHint() const { - if(cachedMinimumSizeHint.isEmpty()) - { - ensurePolished(); - - const QFontMetrics fm(fontMetrics()); - int h = lineEdit()->minimumSizeHint().height(); - int w = fm.width(BitcoinUnits::format(BitcoinUnits::DASH, BitcoinUnits::maxMoney(), false, BitcoinUnits::separatorAlways)); - w += 2; // cursor blinking space - - QStyleOptionSpinBox opt; - initStyleOption(&opt); - QSize hint(w, h); - QSize extra(35, 6); - opt.rect.setSize(hint + extra); - extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt, - QStyle::SC_SpinBoxEditField, this).size(); - // get closer to final result by repeating the calculation - opt.rect.setSize(hint + extra); - extra += hint - style()->subControlRect(QStyle::CC_SpinBox, &opt, - QStyle::SC_SpinBoxEditField, this).size(); - hint += extra; - hint.setHeight(h); - - opt.rect = rect(); - - cachedMinimumSizeHint = style()->sizeFromContents(QStyle::CT_SpinBox, &opt, hint, this) - .expandedTo(QApplication::globalStrut()); - } - return cachedMinimumSizeHint; + ensurePolished(); + const QFontMetrics fm(fontMetrics()); + int h = 0; + int w = fm.width(BitcoinUnits::format(BitcoinUnits::DASH, BitcoinUnits::maxMoney(), false, BitcoinUnits::separatorAlways)); + w += 2; // cursor blinking space + w += GUIUtil::dashThemeActive() ? 24 : 0; // counteract padding from css + return QSize(w, h); } private: int currentUnit; - CAmount singleStep; - mutable QSize cachedMinimumSizeHint; - - /** - * Parse a string into a number of base monetary units and - * return validity. - * @note Must return 0 if !valid. - */ - CAmount parse(const QString &text, bool *valid_out=0) const - { - CAmount val = 0; - bool valid = BitcoinUnits::parse(currentUnit, text, &val); - if(valid) - { - if(val < 0 || val > BitcoinUnits::maxMoney()) - valid = false; - } - if(valid_out) - *valid_out = valid; - return valid ? val : 0; - } protected: bool event(QEvent *event) @@ -158,30 +136,18 @@ class AmountSpinBox: public QAbstractSpinBox { // Translate a comma into a period QKeyEvent periodKeyEvent(event->type(), Qt::Key_Period, keyEvent->modifiers(), ".", keyEvent->isAutoRepeat(), keyEvent->count()); - return QAbstractSpinBox::event(&periodKeyEvent); + return QLineEdit::event(&periodKeyEvent); + } + if(keyEvent->key() == Qt::Key_Enter || keyEvent->key() == Qt::Key_Return) + { + clearFocus(); } } - return QAbstractSpinBox::event(event); - } - - StepEnabled stepEnabled() const - { - if (isReadOnly()) // Disable steps when AmountSpinBox is read-only - return StepNone; - if (text().isEmpty()) // Allow step-up with empty field - return StepUpEnabled; - - StepEnabled rv = 0; - bool valid = false; - CAmount val = value(&valid); - if(valid) + if (event->type() == QEvent::FocusOut) { - if(val > 0) - rv |= StepDownEnabled; - if(val < BitcoinUnits::maxMoney()) - rv |= StepUpEnabled; + fixup(text()); } - return rv; + return QLineEdit::event(event); } Q_SIGNALS: @@ -194,18 +160,17 @@ BitcoinAmountField::BitcoinAmountField(QWidget *parent) : QWidget(parent), amount(0) { - amount = new AmountSpinBox(this); + amount = new AmountLineEdit(this); amount->setLocale(QLocale::c()); amount->installEventFilter(this); - amount->setMaximumWidth(240); + amount->setMaximumWidth(300); + + units = new BitcoinUnits(this); QHBoxLayout *layout = new QHBoxLayout(this); + layout->setSpacing(0); + layout->setMargin(0); layout->addWidget(amount); - unit = new QValueComboBox(this); - unit->setModel(new BitcoinUnits(this)); - layout->addWidget(unit); - layout->addStretch(1); - layout->setContentsMargins(0,0,0,0); setLayout(layout); @@ -214,22 +179,16 @@ BitcoinAmountField::BitcoinAmountField(QWidget *parent) : // If one if the widgets changes, the combined content changes as well connect(amount, SIGNAL(valueChanged()), this, SIGNAL(valueChanged())); - connect(unit, SIGNAL(currentIndexChanged(int)), this, SLOT(unitChanged(int))); - - // Set default based on configuration - unitChanged(unit->currentIndex()); } void BitcoinAmountField::clear() { amount->clear(); - unit->setCurrentIndex(0); } void BitcoinAmountField::setEnabled(bool fEnabled) { amount->setEnabled(fEnabled); - unit->setEnabled(fEnabled); } bool BitcoinAmountField::validate() @@ -261,8 +220,7 @@ bool BitcoinAmountField::eventFilter(QObject *object, QEvent *event) QWidget *BitcoinAmountField::setupTabChain(QWidget *prev) { QWidget::setTabOrder(prev, amount); - QWidget::setTabOrder(amount, unit); - return unit; + return amount; } CAmount BitcoinAmountField::value(bool *valid_out) const @@ -283,20 +241,17 @@ void BitcoinAmountField::setReadOnly(bool fReadOnly) void BitcoinAmountField::unitChanged(int idx) { // Use description tooltip for current unit for the combobox - unit->setToolTip(unit->itemData(idx, Qt::ToolTipRole).toString()); + amount->setToolTip(units->data(idx, Qt::ToolTipRole).toString()); // Determine new unit ID - int newUnit = unit->itemData(idx, BitcoinUnits::UnitRole).toInt(); + int newUnit = units->data(idx, BitcoinUnits::UnitRole).toInt(); + + amount->setPlaceholderText(tr("Amount in ") + units->data(idx,Qt::DisplayRole).toString()); amount->setDisplayUnit(newUnit); } void BitcoinAmountField::setDisplayUnit(int newUnit) { - unit->setValue(newUnit); -} - -void BitcoinAmountField::setSingleStep(const CAmount& step) -{ - amount->setSingleStep(step); + unitChanged(newUnit); } diff --git a/src/qt/bitcoinamountfield.h b/src/qt/bitcoinamountfield.h index 659ecb416ba7..8d7d44221327 100644 --- a/src/qt/bitcoinamountfield.h +++ b/src/qt/bitcoinamountfield.h @@ -7,9 +7,11 @@ #include +#include #include -class AmountSpinBox; +class AmountLineEdit; +class BitcoinUnits; QT_BEGIN_NAMESPACE class QValueComboBox; @@ -31,9 +33,6 @@ class BitcoinAmountField: public QWidget CAmount value(bool *value=0) const; void setValue(const CAmount& value); - /** Set single step in satoshis **/ - void setSingleStep(const CAmount& step); - /** Make read-only **/ void setReadOnly(bool fReadOnly); @@ -64,12 +63,10 @@ class BitcoinAmountField: public QWidget bool eventFilter(QObject *object, QEvent *event); private: - AmountSpinBox *amount; - QValueComboBox *unit; + AmountLineEdit *amount; + BitcoinUnits *units; -private Q_SLOTS: void unitChanged(int idx); - }; #endif // BITCOIN_QT_BITCOINAMOUNTFIELD_H From 0aa81decd7a9c27649972354edda5b14c76aaaef Mon Sep 17 00:00:00 2001 From: xdustinface Date: Wed, 17 Jun 2020 01:59:43 +0200 Subject: [PATCH 4/6] qt: Removed leftover from legacy BitcoinAmountField --- src/qt/sendcoinsdialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index d2cf188c0b89..9a4952b94c01 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -217,7 +217,7 @@ void SendCoinsDialog::setModel(WalletModel *_model) connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(setMinimumFee())); connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(updateFeeSectionControls())); connect(ui->checkBoxMinimumFee, SIGNAL(stateChanged(int)), this, SLOT(coinControlUpdateLabels())); - ui->customFee->setSingleStep(GetRequiredFee(1000)); + updateFeeSectionControls(); updateMinFeeLabel(); updateSmartFeeLabel(); From d2454c72d532d6851ee7063c62b7fb4185df13d2 Mon Sep 17 00:00:00 2001 From: xdustinface Date: Wed, 17 Jun 2020 01:57:43 +0200 Subject: [PATCH 5/6] qt: Move amount field into a Hlayout with a spacer (ReveiveCoinsDialog) Make sure it does not get stretched above the in AmountLineEdit::minimumSizeHint() calculated size. --- src/qt/forms/receivecoinsdialog.ui | 37 ++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/src/qt/forms/receivecoinsdialog.ui b/src/qt/forms/receivecoinsdialog.ui index 821e0182aacb..3293e9e6f48e 100644 --- a/src/qt/forms/receivecoinsdialog.ui +++ b/src/qt/forms/receivecoinsdialog.ui @@ -97,13 +97,6 @@ - - - - An optional amount to request. Leave this empty or zero to not request a specific amount. - - - @@ -160,6 +153,36 @@ + + + + 0 + + + 0 + + + + + An optional amount to request. Leave this empty or zero to not request a specific amount. + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + From 4b174daa4ab6312bed5f3263011723c28bfbf780 Mon Sep 17 00:00:00 2001 From: xdustinface Date: Wed, 17 Jun 2020 02:03:41 +0200 Subject: [PATCH 6/6] qt: Removed obsolete workaround related to BitcoinAmountField Its fixed now with the change to a normal line edit. --- src/qt/res/css/general.css | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/qt/res/css/general.css b/src/qt/res/css/general.css index eaa4ec341d06..1982e5555f9e 100644 --- a/src/qt/res/css/general.css +++ b/src/qt/res/css/general.css @@ -1071,11 +1071,6 @@ BitcoinAmountField ******************************************************/ BitcoinAmountField{ - /* This is a hacky way to make sure BitcoinAmountField's - * shows completely. - * TODO: Fix the issue properly. - */ - margin-bottom: 5px; } /******************************************************