From 04e43f92506f50334c178d9c37b0c6518b31d59a Mon Sep 17 00:00:00 2001 From: random-zebra Date: Tue, 27 Apr 2021 20:46:10 +0200 Subject: [PATCH 1/5] [CSS] Prepare styling for btn-list-menu::checked (font-size/color) We will make the 'subtractFeeFromAmount' a checkable button in the menu for multiple recipient rows --- src/qt/pivx/res/css/style_dark.css | 5 +++++ src/qt/pivx/res/css/style_light.css | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/src/qt/pivx/res/css/style_dark.css b/src/qt/pivx/res/css/style_dark.css index d127a85b8193c..2e17f1bb032ce 100644 --- a/src/qt/pivx/res/css/style_dark.css +++ b/src/qt/pivx/res/css/style_dark.css @@ -3068,6 +3068,11 @@ HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ color: #5c4b7d; } +*[cssClass="btn-list-menu"]:checked{ + font-size:16px; + color:#b088ff; +} + /*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH diff --git a/src/qt/pivx/res/css/style_light.css b/src/qt/pivx/res/css/style_light.css index 5f8ee68baf655..0d3de49bcc227 100644 --- a/src/qt/pivx/res/css/style_light.css +++ b/src/qt/pivx/res/css/style_light.css @@ -3066,6 +3066,11 @@ HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ color: #5c4b7d; } +*[cssClass="btn-list-menu"]:checked{ + font-size:16px; + color: #b088ff; +} + /*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH HH EMPTY LIST From c8e74e03b3400ec82325c788aa750e3d40050986 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Tue, 27 Apr 2021 20:51:48 +0200 Subject: [PATCH 2/5] [GUI] Add checkboxSubtractFeeFromAmount checkbox in sendmultirow Visible when single recipient. Its checked state returns whether or not to subtract the fee from the recipient amount. SendMultiRow::toggleSubtractFeeFromAmount is not connected for now. It will be connected with the contextual menu, to set per-recipient subtract-fee-from-amount, when there are multiple rows. --- src/qt/pivx/forms/sendmultirow.ui | 10 ++++++++++ src/qt/pivx/sendconfirmdialog.cpp | 16 ++++++++++++++-- src/qt/pivx/sendmultirow.cpp | 12 ++++++++++++ src/qt/pivx/sendmultirow.h | 2 ++ src/qt/walletmodel.cpp | 4 ++-- src/qt/walletmodel.h | 3 +++ 6 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/qt/pivx/forms/sendmultirow.ui b/src/qt/pivx/forms/sendmultirow.ui index 55807066364e6..83272fe04631d 100644 --- a/src/qt/pivx/forms/sendmultirow.ui +++ b/src/qt/pivx/forms/sendmultirow.ui @@ -347,6 +347,16 @@ padding:0px; 0 + + + + The fee will be deducted from the amount being sent. The recipient will receive less PIV than you enter in the amount field. If multiple recipients are selected, the fee is split equally. + + + Subtract fee from amount + + + diff --git a/src/qt/pivx/sendconfirmdialog.cpp b/src/qt/pivx/sendconfirmdialog.cpp index 984a9b6e6fb5d..dfe6c02582f66 100644 --- a/src/qt/pivx/sendconfirmdialog.cpp +++ b/src/qt/pivx/sendconfirmdialog.cpp @@ -183,14 +183,26 @@ void TxDetailDialog::setData(WalletModel *_model, WalletModelTransaction* _tx) this->model = _model; this->tx = _tx; CAmount txFee = tx->getTransactionFee(); - CAmount totalAmount = tx->getTotalTransactionAmount() + txFee; // inputs label CTransactionRef walletTx = tx->getTransaction(); setInputsType(walletTx); + bool fSubtractFee = false; + const QList& recipients = tx->getRecipients(); + for (const SendCoinsRecipient& rec : recipients) { + if (rec.fSubtractFee) { + fSubtractFee = true; + break; + } + } + + CAmount totalAmount = tx->getTotalTransactionAmount(); + if (!fSubtractFee) totalAmount += txFee; + ui->textAmount->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, totalAmount, false, BitcoinUnits::separatorAlways) + " (Fee included)"); - int nRecipients = tx->getRecipients().size(); + + int nRecipients = recipients.size(); if (nRecipients == 1) { const SendCoinsRecipient& recipient = tx->getRecipients().at(0); if (recipient.isP2CS) { diff --git a/src/qt/pivx/sendmultirow.cpp b/src/qt/pivx/sendmultirow.cpp index a95cd6ce3b9bb..a91f472b3b67c 100644 --- a/src/qt/pivx/sendmultirow.cpp +++ b/src/qt/pivx/sendmultirow.cpp @@ -225,6 +225,7 @@ SendCoinsRecipient SendMultiRow::getValue() recipient.amount = getAmountValue(); auto dest = Standard::DecodeDestination(recipient.address.toStdString()); recipient.isShieldedAddr = boost::get(&dest); + recipient.fSubtractFee = getSubtractFeeFromAmount(); return recipient; } @@ -263,6 +264,11 @@ int SendMultiRow::getNumber() return number; } +bool SendMultiRow::getSubtractFeeFromAmount() const +{ + return ui->checkboxSubtractFeeFromAmount->isChecked(); +} + void SendMultiRow::setAddress(const QString& address) { ui->lineEditAddress->setText(address); @@ -274,6 +280,12 @@ void SendMultiRow::setAmount(const QString& amount) ui->lineEditAmount->setText(amount); } +void SendMultiRow::toggleSubtractFeeFromAmount() +{ + bool old = ui->checkboxSubtractFeeFromAmount->isChecked(); + ui->checkboxSubtractFeeFromAmount->setChecked(!old); +} + void SendMultiRow::setAddressAndLabelOrDescription(const QString& address, const QString& message) { QString label = walletModel->getAddressTableModel()->labelForAddress(address); diff --git a/src/qt/pivx/sendmultirow.h b/src/qt/pivx/sendmultirow.h index 5a6f5ad0f55b3..9bb34c5d3fbf5 100644 --- a/src/qt/pivx/sendmultirow.h +++ b/src/qt/pivx/sendmultirow.h @@ -50,11 +50,13 @@ class SendMultiRow : public PWidget void setAmount(const QString& amount); void setAddressAndLabelOrDescription(const QString& address, const QString& message); void setFocus(); + void toggleSubtractFeeFromAmount(); QRect getEditLineRect(); int getEditHeight(); int getEditWidth(); int getMenuBtnWidth(); + bool getSubtractFeeFromAmount() const; // Return true if memo was set and false if it was cleared. bool launchMemoDialog(); diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 567ccf24b6801..d5edb32f6f6d1 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -488,7 +488,7 @@ WalletModel::SendCoinsReturn WalletModel::prepareTransaction(WalletModelTransact // Regular P2PK or P2PKH scriptPubKey = GetScriptForDestination(out); } - vecSend.emplace_back(scriptPubKey, rcp.amount, false); + vecSend.emplace_back(scriptPubKey, rcp.amount, rcp.fSubtractFee); total += rcp.amount; } @@ -598,9 +598,9 @@ OperationResult WalletModel::PrepareShieldedTransaction(WalletModelTransaction* const CCoinControl* coinControl) { // Load shieldedAddrRecipients. - bool fSubtractFeeFromAmount{false}; std::vector recipients; for (const auto& recipient : modelTransaction->getRecipients()) { + bool fSubtractFeeFromAmount = recipient.fSubtractFee; if (recipient.isShieldedAddr) { auto pa = KeyIO::DecodeSaplingPaymentAddress(recipient.address.toStdString()); if (!pa) return errorOut("Error, invalid shielded address"); diff --git a/src/qt/walletmodel.h b/src/qt/walletmodel.h index 4474727deef73..1fa09393584bf 100644 --- a/src/qt/walletmodel.h +++ b/src/qt/walletmodel.h @@ -71,6 +71,9 @@ class SendCoinsRecipient // Quick flag to not have to check the address type more than once. bool isShieldedAddr{false}; + // Whether to subtract the tx fee from this recipient + bool fSubtractFee{false}; + // Amount CAmount amount{0}; // If from a payment request, this is used for storing the memo From 26ac915b83fecd1f025c86423de5555ef662c238 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Tue, 27 Apr 2021 20:53:34 +0200 Subject: [PATCH 3/5] [GUI] Add checkable btn in the contextual menu, for sffa with multirows --- src/qt/pivx/send.cpp | 14 +++++++++++++- src/qt/pivx/send.h | 1 + src/qt/pivx/tooltipmenu.cpp | 6 ++++++ src/qt/pivx/tooltipmenu.h | 1 + 4 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/qt/pivx/send.cpp b/src/qt/pivx/send.cpp index af8407289cd02..9155d1c0ae821 100644 --- a/src/qt/pivx/send.cpp +++ b/src/qt/pivx/send.cpp @@ -863,14 +863,19 @@ void SendWidget::onMenuClicked(SendMultiRow* entry) this->menu = new TooltipMenu(window, this); this->menu->setCopyBtnText(tr("Add Memo")); this->menu->setEditBtnText(tr("Save contact")); - this->menu->setMinimumSize(this->menu->width() + 30,this->menu->height()); + this->menu->setLastBtnVisible(true); + this->menu->setLastBtnText(tr("Subtract fee")); + this->menu->setMinimumHeight(157); + this->menu->setMinimumSize(this->menu->width() + 30, this->menu->height()); connect(this->menu, &TooltipMenu::message, this, &AddressesWidget::message); connect(this->menu, &TooltipMenu::onEditClicked, this, &SendWidget::onContactMultiClicked); connect(this->menu, &TooltipMenu::onDeleteClicked, this, &SendWidget::onDeleteClicked); connect(this->menu, &TooltipMenu::onCopyClicked, this, &SendWidget::onEntryMemoClicked); + connect(this->menu, &TooltipMenu::onLastClicked, this, &SendWidget::onSubtractFeeFromAmountChecked); } else { this->menu->hide(); } + this->menu->setLastBtnCheckable(true, entry->getSubtractFeeFromAmount()); menu->move(pos); menu->show(); } @@ -932,6 +937,13 @@ void SendWidget::onEntryMemoClicked() } } +void SendWidget::onSubtractFeeFromAmountChecked() +{ + if (focusedEntry) { + focusedEntry->toggleSubtractFeeFromAmount(); + } +} + void SendWidget::onDeleteClicked() { if (focusedEntry) { diff --git a/src/qt/pivx/send.h b/src/qt/pivx/send.h index fcc4f90384082..6cf8d6129e919 100644 --- a/src/qt/pivx/send.h +++ b/src/qt/pivx/send.h @@ -81,6 +81,7 @@ private Q_SLOTS: void onContactMultiClicked(); void onDeleteClicked(); void onEntryMemoClicked(); + void onSubtractFeeFromAmountChecked(); void onResetCustomOptions(bool fRefreshAmounts); void onResetSettings(); diff --git a/src/qt/pivx/tooltipmenu.cpp b/src/qt/pivx/tooltipmenu.cpp index f0b1722042b37..2ca673048b3fc 100644 --- a/src/qt/pivx/tooltipmenu.cpp +++ b/src/qt/pivx/tooltipmenu.cpp @@ -40,6 +40,12 @@ void TooltipMenu::setLastBtnText(QString btnText, int minHeight){ ui->btnLast->setMinimumHeight(minHeight); } +void TooltipMenu::setLastBtnCheckable(bool checkable, bool isChecked) +{ + ui->btnLast->setCheckable(checkable); + ui->btnLast->setChecked(isChecked); +} + void TooltipMenu::setCopyBtnVisible(bool visible){ ui->btnCopy->setVisible(visible); } diff --git a/src/qt/pivx/tooltipmenu.h b/src/qt/pivx/tooltipmenu.h index 00f0c460ffb5f..8b5d339ee65e8 100644 --- a/src/qt/pivx/tooltipmenu.h +++ b/src/qt/pivx/tooltipmenu.h @@ -39,6 +39,7 @@ class TooltipMenu : public PWidget void setDeleteBtnVisible(bool visible); void setEditBtnVisible(bool visible); void setLastBtnVisible(bool visible); + void setLastBtnCheckable(bool checkable, bool isChecked); Q_SIGNALS: void onDeleteClicked(); From 3f45e0921fadba9107339c1ccf6bdb963d338c36 Mon Sep 17 00:00:00 2001 From: furszy Date: Mon, 5 Jul 2021 12:43:21 -0300 Subject: [PATCH 4/5] GUI: Add styling for subtract fee from amount checkbox for light and dark themes. * Aligned the checkbox checked/unchecked text color and check image to the screen styling. * Added checkbox hover selector state. --- src/Makefile.qt.include | 1 + src/qt/pivx.qrc | 1 + src/qt/pivx/res/css/style_dark.css | 28 +++++++++++++++++++++- src/qt/pivx/res/css/style_light.css | 24 ++++++++++++++++++- src/qt/pivx/res/img/ic-check-box-light.svg | 11 +++++++++ src/qt/pivx/sendmultirow.cpp | 2 ++ 6 files changed, 65 insertions(+), 2 deletions(-) create mode 100755 src/qt/pivx/res/img/ic-check-box-light.svg diff --git a/src/Makefile.qt.include b/src/Makefile.qt.include index d8f6e1a899ec1..d473c0419e86a 100644 --- a/src/Makefile.qt.include +++ b/src/Makefile.qt.include @@ -420,6 +420,7 @@ RES_ICONS = \ qt/pivx/res/img/ic-switch-on.svg \ qt/pivx/res/img/img-qr-test.png \ qt/pivx/res/img/ic-check-box.svg \ + qt/pivx/res/img/ic-check-box-light.svg \ qt/pivx/res/img/ic-check-box-dark-active.svg \ qt/pivx/res/img/ic-check-box-indeterminate.svg \ qt/pivx/res/img/ic-check-box-liliac-indeterminate.svg \ diff --git a/src/qt/pivx.qrc b/src/qt/pivx.qrc index 5202fb878e228..7d6ccdfef7d32 100644 --- a/src/qt/pivx.qrc +++ b/src/qt/pivx.qrc @@ -62,6 +62,7 @@ pivx/res/img/ic-arrow-white-right.svg pivx/res/img/ic-check-active.svg pivx/res/img/ic-check-box.svg + pivx/res/img/ic-check-box-light.svg pivx/res/img/ic-check-box-liliac-indeterminate.svg pivx/res/img/ic-check-connect-off.svg pivx/res/img/ic-check-connect.svg diff --git a/src/qt/pivx/res/css/style_dark.css b/src/qt/pivx/res/css/style_dark.css index 2e17f1bb032ce..c4e3ebfd7f77e 100644 --- a/src/qt/pivx/res/css/style_dark.css +++ b/src/qt/pivx/res/css/style_dark.css @@ -2049,7 +2049,7 @@ QCheckBox { color:#FFFFFF; } -QCheckBox:checked { +QCheckBox:checked { spacing: 5px; font-size:18px; color:#b088ff; @@ -2084,6 +2084,32 @@ QCheckBox[cssClass="btn-watch-password"]::indicator:checked { image: url("://ic-watch-password-white"); } +QCheckBox[cssClass="combo-light"] { + spacing: 5px; + font-size:18px; + color: #807b8a; +} + +QCheckBox[cssClass="combo-light"]:checked { + spacing: 5px; + font-size:18px; + color:#b088ff; +} + +QCheckBox[cssClass="combo-light"]::indicator:unchecked { + image: url("://ic-check-box-light"); +} + +QCheckBox[cssClass="combo-light"]:hover { + spacing: 5px; + font-size:18px; + color: #bababa; +} + +QCheckBox[cssClass="combo-light"]::indicator:unchecked:hover { + image: url("://ic-check-box"); +} + /*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH HH REQUEST DIALOG HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ diff --git a/src/qt/pivx/res/css/style_light.css b/src/qt/pivx/res/css/style_light.css index 0d3de49bcc227..6dbd2cbe59173 100644 --- a/src/qt/pivx/res/css/style_light.css +++ b/src/qt/pivx/res/css/style_light.css @@ -2049,7 +2049,7 @@ QCheckBox { color:#707070; } -QCheckBox:checked { +QCheckBox:checked { spacing: 5px; font-size:18px; color:#5c4b7d; @@ -2084,6 +2084,28 @@ QCheckBox[cssClass="btn-watch-password"]::indicator:checked { image: url("://ic-watch-password"); } +QCheckBox[cssClass="combo-light"] { + spacing: 5px; + font-size:18px; + color:#bababa; +} + +QCheckBox[cssClass="combo-light"]:checked { + spacing: 5px; + font-size:18px; + color:#707070; +} + +QCheckBox[cssClass="combo-light"]:hover { + spacing: 5px; + font-size:18px; + color: #707070; +} + +QCheckBox[cssClass="combo-light"]::indicator:unchecked:hover { + image: url("://ic-check-box-light"); +} + /*HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH HH REQUEST DIALOG HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH*/ diff --git a/src/qt/pivx/res/img/ic-check-box-light.svg b/src/qt/pivx/res/img/ic-check-box-light.svg new file mode 100755 index 0000000000000..804ce4a64ffa1 --- /dev/null +++ b/src/qt/pivx/res/img/ic-check-box-light.svg @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/src/qt/pivx/sendmultirow.cpp b/src/qt/pivx/sendmultirow.cpp index a91f472b3b67c..3a80e657f947a 100644 --- a/src/qt/pivx/sendmultirow.cpp +++ b/src/qt/pivx/sendmultirow.cpp @@ -34,6 +34,8 @@ SendMultiRow::SendMultiRow(PIVXGUI* _window, PWidget *parent) : // future: when we get a designer, this should have another icon. A "memo" icon instead of a "+" setCssProperty(ui->btnAddMemo, "btn-secundary-add"); + setCssProperty(ui->checkboxSubtractFeeFromAmount, "combo-light"); + // Button menu setCssProperty(ui->btnMenu, "btn-menu"); ui->btnMenu->setVisible(false); From 3e860c5e1f8ebd0c10a6061e2f1d41b8fe049934 Mon Sep 17 00:00:00 2001 From: random-zebra Date: Tue, 13 Jul 2021 00:03:06 +0200 Subject: [PATCH 5/5] [GUI] Display actual recipient amount with sffa in confirmation dlg --- src/qt/pivx/sendconfirmdialog.cpp | 19 +++++++------------ src/qt/walletmodeltransaction.cpp | 9 +++++++++ src/qt/walletmodeltransaction.h | 3 +++ 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/qt/pivx/sendconfirmdialog.cpp b/src/qt/pivx/sendconfirmdialog.cpp index dfe6c02582f66..0b22800fedc01 100644 --- a/src/qt/pivx/sendconfirmdialog.cpp +++ b/src/qt/pivx/sendconfirmdialog.cpp @@ -188,23 +188,15 @@ void TxDetailDialog::setData(WalletModel *_model, WalletModelTransaction* _tx) CTransactionRef walletTx = tx->getTransaction(); setInputsType(walletTx); - bool fSubtractFee = false; - const QList& recipients = tx->getRecipients(); - for (const SendCoinsRecipient& rec : recipients) { - if (rec.fSubtractFee) { - fSubtractFee = true; - break; - } - } - CAmount totalAmount = tx->getTotalTransactionAmount(); - if (!fSubtractFee) totalAmount += txFee; + if (tx->subtractFeeFromRecipents() == 0) totalAmount += txFee; ui->textAmount->setText(BitcoinUnits::formatWithUnit(nDisplayUnit, totalAmount, false, BitcoinUnits::separatorAlways) + " (Fee included)"); + const QList& recipients = tx->getRecipients(); int nRecipients = recipients.size(); if (nRecipients == 1) { - const SendCoinsRecipient& recipient = tx->getRecipients().at(0); + const SendCoinsRecipient& recipient = recipients.at(0); if (recipient.isP2CS) { ui->labelSend->setText(tr("Delegating to")); } @@ -337,11 +329,14 @@ void TxDetailDialog::onOutputsClicked() // If the there is a model tx, then this is a confirmation dialog if (tx) { const QList& recipients = tx->getRecipients(); + unsigned int sffa = tx->subtractFeeFromRecipents(); + CAmount rcp_fee = (sffa > 0) ? (tx->getTransactionFee() / sffa) : 0; for (int i = 0; i < recipients.size(); ++i) { const auto& recipient = recipients[i]; + CAmount rcp_amt = recipient.amount - (recipient.fSubtractFee ? rcp_fee : 0); int charsSize = recipient.isShieldedAddr ? 18 : 16; QString labelRes = recipient.address.left(charsSize) + "..." + recipient.address.right(charsSize); - appendOutput(layoutGrid, i, labelRes, recipient.amount, nDisplayUnit); + appendOutput(layoutGrid, i, labelRes, rcp_amt, nDisplayUnit); } } else { // Tx detail dialog diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index 62cd2da3e9151..a4572cf4f64e7 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -43,6 +43,15 @@ void WalletModelTransaction::setTransactionFee(const CAmount& newFee) fee = newFee; } +unsigned int WalletModelTransaction::subtractFeeFromRecipents() const +{ + unsigned int count = 0; + for (const SendCoinsRecipient& rcp : recipients) { + if (rcp.fSubtractFee) count++; + } + return count; +} + CAmount WalletModelTransaction::getTotalTransactionAmount() { CAmount totalTransactionAmount = 0; diff --git a/src/qt/walletmodeltransaction.h b/src/qt/walletmodeltransaction.h index 93fa24b5e5b6d..3b668b28cd140 100644 --- a/src/qt/walletmodeltransaction.h +++ b/src/qt/walletmodeltransaction.h @@ -39,6 +39,9 @@ class WalletModelTransaction CTransactionRef& getTransaction(); + // return the number of recipients with subtract-fee-from-amount + unsigned int subtractFeeFromRecipents() const; + // Whether should create a +v2 tx or go simple and create a v1. bool useV2{false}; bool fIsStakeDelegationVoided{false};