From b22aa1813c8cc2d1a1b0aa3d235cd648e23e85d6 Mon Sep 17 00:00:00 2001 From: dustinface <35775977+xdustinface@users.noreply.github.com> Date: Fri, 25 Sep 2020 18:04:53 +0200 Subject: [PATCH] qt: Finetune OverviewPage (#3715) * qt: Adjust "Recent Transactions" in Overview tab Make sure they follow the same format as the transactions in TransactionsView. - Removed the transaction type representing arrows - Apply the same coloring like like in the transaction tab for the different transaction types (orange = internal, red = outgoing, green = incoming) * qt: Cleanup layout of OverviewPage in css * qt: Add three spacer (left, middle, right) and adjust layout stretch. This allows to have the elements on the screen aligned symetrically around the center independent from the window size/resizing. * qt: Inrease date/amount size for "Recent Transactions" in Overview tab * qt: Inrease number of "Recent Transactions" displayed in Overview tab Just to fill the empty space * qt: Make sure PS elements show as expected and adjust number of recent transactions based on PS * qt: Adjust transaction entry generation Co-Authored-By: UdjinM6 * qt: Adjust warning message box Co-Authored-By: UdjinM6 * Move tx list style to css * Fix tx list style for the traditional theme * Drop (no longer needed?) min height offset in SetupTransactionList Can't reproduce the tx list scrolling issue anymore * Avoid recreating transaction filter from scratch every time SetupTransactionList is called We call SetupTransactionList every second now (from privateSendStatus()) and this makes GUI unresponsive for huge wallets (I have ~400k txes in my testnet wallet) because of filter recreation/sorting. There is no need to go through all setup steps really, simply updating the limit works just fine and fixes the issue. * qt: Fix an `if` statement * qt: Just some refactoring * fix code style * bail out if `filter->rowCount() == nNumItems` * qt: Make sure number of transactions is always correct * Drop spacer to let recent tx list occupy max height available * TransactionFilterProxy::setLimit should emit signals to let coresponding layouts update themselves https://doc.qt.io/qt-5/qabstractitemmodel.html#layoutAboutToBeChanged https://doc.qt.io/qt-5/qabstractitemmodel.html#layoutChanged Co-authored-by: UdjinM6 --- src/qt/forms/overviewpage.ui | 66 +++++++---- src/qt/overviewpage.cpp | 182 +++++++++++++++++------------- src/qt/res/css/general.css | 50 ++++---- src/qt/res/css/traditional.css | 14 +++ src/qt/transactionfilterproxy.cpp | 2 + 5 files changed, 187 insertions(+), 127 deletions(-) diff --git a/src/qt/forms/overviewpage.ui b/src/qt/forms/overviewpage.ui index b19e91a685..355d321d0f 100644 --- a/src/qt/forms/overviewpage.ui +++ b/src/qt/forms/overviewpage.ui @@ -25,9 +25,6 @@ false - - QLabel { background-color: qlineargradient(x1: 0, y1: 0, x2: 1, y2: 0, stop:0 #F0D0A0, stop:1 #F8D488); color:#000000; } - true @@ -40,7 +37,23 @@ - + + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 10 + 20 + + + + @@ -563,6 +576,19 @@ + + + + Qt::Horizontal + + + + 10 + 20 + + + + @@ -613,9 +639,6 @@ - - QListView { background: transparent; } - QFrame::NoFrame @@ -633,21 +656,24 @@ - - - - Qt::Vertical - - - - 20 - 40 - - - - + + + + Qt::Horizontal + + + QSizePolicy::Preferred + + + + 10 + 20 + + + + diff --git a/src/qt/overviewpage.cpp b/src/qt/overviewpage.cpp index 7e5ef9e655..4237061e77 100644 --- a/src/qt/overviewpage.cpp +++ b/src/qt/overviewpage.cpp @@ -24,10 +24,10 @@ #include #include -#define ICON_OFFSET 16 -#define DECORATION_SIZE 54 -#define NUM_ITEMS 5 -#define NUM_ITEMS_ADV 7 +#define ITEM_HEIGHT 54 +#define NUM_ITEMS_DISABLED 5 +#define NUM_ITEMS_ENABLED_NORMAL 7 +#define NUM_ITEMS_ENABLED_ADVANCED 9 class TxViewDelegate : public QAbstractItemDelegate { @@ -44,70 +44,65 @@ public: { painter->save(); - QIcon icon = qvariant_cast(index.data(TransactionTableModel::RawDecorationRole)); QRect mainRect = option.rect; - mainRect.moveLeft(ICON_OFFSET); - QRect decorationRect(mainRect.topLeft(), QSize(DECORATION_SIZE, DECORATION_SIZE)); - int xspace = DECORATION_SIZE + 8; - int ypad = 6; + int xspace = 8; + int ypad = 8; int halfheight = (mainRect.height() - 2*ypad)/2; - QRect amountRect(mainRect.left() + xspace, mainRect.top()+ypad, mainRect.width() - xspace - ICON_OFFSET, halfheight); - QRect addressRect(mainRect.left() + xspace, mainRect.top()+ypad+halfheight, mainRect.width() - xspace, halfheight); - icon = QIcon(icon); - icon.paint(painter, decorationRect); + QRect rectTopHalf(mainRect.left() + xspace, mainRect.top() + ypad, mainRect.width() - xspace, halfheight); + QRect rectBottomHalf(mainRect.left() + xspace, mainRect.top() + ypad + halfheight + 5, mainRect.width() - xspace, halfheight); + QRect rectBounding; + QColor colorForeground; + QFont fontInitial = painter->font(); - QDateTime date = index.data(TransactionTableModel::DateRole).toDateTime(); - QString address = index.data(Qt::DisplayRole).toString(); - qint64 amount = index.data(TransactionTableModel::AmountRole).toLongLong(); - bool confirmed = index.data(TransactionTableModel::ConfirmedRole).toBool(); - QVariant value = index.data(Qt::ForegroundRole); - QColor foreground = GUIUtil::getThemedQColor(GUIUtil::ThemedColor::DEFAULT); - if(value.canConvert()) - { - QBrush brush = qvariant_cast(value); - foreground = brush.color(); - } + // Grab model indexes for desired data from TransactionTableModel + QModelIndex indexDate = index.sibling(index.row(), TransactionTableModel::Date); + QModelIndex indexAmount = index.sibling(index.row(), TransactionTableModel::Amount); + QModelIndex indexAddress = index.sibling(index.row(), TransactionTableModel::ToAddress); - painter->setPen(foreground); - QRect boundingRect; - painter->drawText(addressRect, Qt::AlignLeft|Qt::AlignVCenter, address, &boundingRect); + // Draw first line (with slightly bigger font than the second line will get) + // Content: Date/Time, Optional IS indicator, Amount + QFont font = fontInitial; + font.setPointSize(font.pointSize() * 1.17); + painter->setFont(font); + // Date/Time + colorForeground = qvariant_cast(indexDate.data(Qt::ForegroundRole)); + QString strDate = indexDate.data(Qt::DisplayRole).toString(); + painter->setPen(colorForeground); + painter->drawText(rectTopHalf, Qt::AlignLeft | Qt::AlignVCenter, strDate, &rectBounding); + // Optional IS indicator + QIcon iconInstantSend = qvariant_cast(indexAddress.data(TransactionTableModel::RawDecorationRole)); + QRect rectInstantSend(rectBounding.right() + 5, rectTopHalf.top(), 16, halfheight); + iconInstantSend.paint(painter, rectInstantSend); + // Amount + colorForeground = qvariant_cast(indexAmount.data(Qt::ForegroundRole)); + // Note: do NOT use Qt::DisplayRole, have format properly here + qint64 nAmount = index.data(TransactionTableModel::AmountRole).toLongLong(); + QString strAmount = BitcoinUnits::floorWithUnit(unit, nAmount, true, BitcoinUnits::separatorAlways); + painter->setPen(colorForeground); + painter->drawText(rectTopHalf, Qt::AlignRight | Qt::AlignVCenter, strAmount); + // Draw second line (with the initial font) + // Content: Address/label, Optional Watchonly indicator + painter->setFont(fontInitial); + // Address/Label + colorForeground = qvariant_cast(indexAddress.data(Qt::ForegroundRole)); + QString address = indexAddress.data(Qt::DisplayRole).toString(); + painter->setPen(colorForeground); + painter->drawText(rectBottomHalf, Qt::AlignLeft | Qt::AlignVCenter, address, &rectBounding); + // Optional Watchonly indicator if (index.data(TransactionTableModel::WatchonlyRole).toBool()) { QIcon iconWatchonly = qvariant_cast(index.data(TransactionTableModel::WatchonlyDecorationRole)); - QRect watchonlyRect(boundingRect.right() + 5, mainRect.top()+ypad+halfheight, 16, halfheight); - iconWatchonly.paint(painter, watchonlyRect); + QRect rectWatchonly(rectBounding.right() + 5, rectBottomHalf.top(), 16, halfheight); + iconWatchonly.paint(painter, rectWatchonly); } - if(amount < 0) - { - foreground = GUIUtil::getThemedQColor(GUIUtil::ThemedColor::RED); - } - else if(!confirmed) - { - foreground = GUIUtil::getThemedQColor(GUIUtil::ThemedColor::UNCONFIRMED); - } - else - { - foreground = option.palette.color(QPalette::Text); - } - painter->setPen(foreground); - QString amountText = BitcoinUnits::floorWithUnit(unit, amount, true, BitcoinUnits::separatorAlways); - if(!confirmed) - { - amountText = QString("[") + amountText + QString("]"); - } - painter->drawText(amountRect, Qt::AlignRight|Qt::AlignVCenter, amountText); - - painter->setPen(option.palette.color(QPalette::Text)); - painter->drawText(amountRect, Qt::AlignLeft|Qt::AlignVCenter, GUIUtil::dateTimeStr(date)); - painter->restore(); } inline QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { - return QSize(DECORATION_SIZE, DECORATION_SIZE); + return QSize(ITEM_HEIGHT, ITEM_HEIGHT); } int unit; @@ -151,7 +146,6 @@ OverviewPage::OverviewPage(QWidget* parent) : // Recent transactions ui->listTransactions->setItemDelegate(txdelegate); - ui->listTransactions->setIconSize(QSize(DECORATION_SIZE, DECORATION_SIZE)); // Note: minimum height of listTransactions will be set later in updateAdvancedPSUI() to reflect actual settings ui->listTransactions->setAttribute(Qt::WA_MacShowFocusRect, false); @@ -163,7 +157,7 @@ OverviewPage::OverviewPage(QWidget* parent) : ui->labelTransactionsStatus->setText("(" + tr("out of sync") + ")"); // hide PS frame (helps to preserve saved size) - // we'll setup and make it visible in updateAdvancedPSUI() later + // we'll setup and make it visible in privateSendStatus() later ui->framePrivateSend->setVisible(false); // start with displaying the "out of sync" warnings @@ -304,9 +298,6 @@ void OverviewPage::setWalletModel(WalletModel *model) // explicitly update PS frame and transaction list to reflect actual settings updateAdvancedPSUI(model->getOptionsModel()->getShowAdvancedPSUI()); - // Initialize PS UI - privateSendStatus(true); - if (!CPrivateSendClientOptions::IsEnabled()) return; connect(model->getOptionsModel(), SIGNAL(privateSendRoundsChanged()), this, SLOT(updatePrivateSendProgress())); @@ -459,16 +450,7 @@ void OverviewPage::updatePrivateSendProgress() void OverviewPage::updateAdvancedPSUI(bool fShowAdvancedPSUI) { this->fShowAdvancedPSUI = fShowAdvancedPSUI; - int nNumItems = (!CPrivateSendClientOptions::IsEnabled() || !fShowAdvancedPSUI) ? NUM_ITEMS : NUM_ITEMS_ADV; - SetupTransactionList(nNumItems); - - if (!CPrivateSendClientOptions::IsEnabled()) return; - - ui->framePrivateSend->setVisible(true); - ui->labelCompletitionText->setVisible(fShowAdvancedPSUI); - ui->privateSendProgress->setVisible(fShowAdvancedPSUI); - ui->labelSubmittedDenomText->setVisible(fShowAdvancedPSUI); - ui->labelSubmittedDenom->setVisible(fShowAdvancedPSUI); + privateSendStatus(true); } void OverviewPage::privateSendStatus(bool fForce) @@ -477,13 +459,43 @@ void OverviewPage::privateSendStatus(bool fForce) if(!walletModel) return; - auto tempWidgets = {ui->labelSubmittedDenomText, - ui->labelSubmittedDenom}; + bool fIsEnabled = CPrivateSendClientOptions::IsEnabled(); + ui->framePrivateSend->setVisible(fIsEnabled); + if (!fIsEnabled) { + SetupTransactionList(NUM_ITEMS_DISABLED); + return; + } + + // Wrap all privatesend related widgets we want to show/hide state based. + // Value of the map contains a flag if this widget belongs to the advanced + // PrivateSend UI option or not. True if it does, false if not. + std::map privateSendWidgets = { + {ui->labelCompletitionText, true}, + {ui->privateSendProgress, true}, + {ui->labelSubmittedDenomText, true}, + {ui->labelSubmittedDenom, true}, + {ui->labelAmountAndRoundsText, false}, + {ui->labelAmountRounds, false} + }; auto setWidgetsVisible = [&](bool fVisible) { - for (const auto& it : tempWidgets) { - it->setVisible(fVisible); + static bool fInitial{true}; + static bool fLastVisible{false}; + static bool fLastShowAdvanced{false}; + // Only update the widget's visibility if something changed since the last call of setWidgetsVisible + if (fLastShowAdvanced == fShowAdvancedPSUI && fLastVisible == fVisible) { + if (fInitial) { + fInitial = false; + } else { + return; + } } + // Set visible if: fVisible and not advanced UI element or advanced ui element and advanced ui active + for (const auto& it : privateSendWidgets) { + it.first->setVisible(fVisible && (!it.second || it.second == fShowAdvancedPSUI)); + } + fLastVisible = fVisible; + fLastShowAdvanced = fShowAdvancedPSUI; }; static int64_t nLastDSProgressBlockTime = 0; @@ -520,7 +532,13 @@ void OverviewPage::privateSendStatus(bool fForce) if (fShowAdvancedPSUI) strEnabled += ", " + strKeysLeftText; ui->labelPrivateSendEnabled->setText(strEnabled); + // If mixing isn't active always show the lower number of txes because there are + // anyway the most PS widgets hidden. + SetupTransactionList(NUM_ITEMS_ENABLED_NORMAL); + return; + } else { + SetupTransactionList(fShowAdvancedPSUI ? NUM_ITEMS_ENABLED_ADVANCED : NUM_ITEMS_ENABLED_NORMAL); } // Warn user that wallet is running out of keys @@ -654,22 +672,28 @@ void OverviewPage::togglePrivateSend(){ } } -void OverviewPage::SetupTransactionList(int nNumItems) { - ui->listTransactions->setMinimumHeight(nNumItems * (DECORATION_SIZE + 2)); +void OverviewPage::SetupTransactionList(int nNumItems) +{ + if (walletModel == nullptr || walletModel->getTransactionTableModel() == nullptr) { + return; + } - if(walletModel && walletModel->getOptionsModel()) { - // Set up transaction list + // Set up transaction list + if (filter == nullptr) { filter.reset(new TransactionFilterProxy()); filter->setSourceModel(walletModel->getTransactionTableModel()); - filter->setLimit(nNumItems); filter->setDynamicSortFilter(true); filter->setSortRole(Qt::EditRole); filter->setShowInactive(false); filter->sort(TransactionTableModel::Date, Qt::DescendingOrder); - ui->listTransactions->setModel(filter.get()); - ui->listTransactions->setModelColumn(TransactionTableModel::ToAddress); } + + if (filter->rowCount() == nNumItems) { + return; + } + + filter->setLimit(nNumItems); } void OverviewPage::DisablePrivateSendCompletely() { diff --git a/src/qt/res/css/general.css b/src/qt/res/css/general.css index cee0ac2bb3..fbea9f5c2e 100644 --- a/src/qt/res/css/general.css +++ b/src/qt/res/css/general.css @@ -33,6 +33,7 @@ in the file. # Used colors in general.css for commit 44de8a93f2 #00000000 +#222222 #5e8c41 #a84832 #c79304 @@ -1295,6 +1296,17 @@ QDialog#OptionsDialog QLabel#overriddenByCommandLineInfoLabel { min-width: 550px; } +/****************************************************** + OverviewPage + ******************************************************/ + +QWidget#OverviewPage QLabel#labelAlerts { + background-color: #c79304; + color: #222222; + border-radius: 5px; + padding: 5px; + } + /****************************************************** OverviewPage Balances ******************************************************/ @@ -1304,21 +1316,18 @@ QWidget .QFrame#frame { /* Wallet Balance */ } QWidget .QFrame#frame > .QLabel { - min-width: 100px; - min-height: 25px; + min-width: 60px; + min-height: 26px; } QWidget .QFrame#frame .QLabel#label_5 { /* Wallet Label */ - min-width: 180px; margin-top: 0; margin-right: 5px; - padding-right: 5px; } QWidget .QFrame#frame .QLabel#labelWalletStatus { /* Wallet Sync Status */ qproperty-alignment: 'AlignVCenter | AlignLeft'; color: #a84832; - margin-left: 3px; } QWidget .QFrame#frame .QLabel#labelSpendable { /* Spendable Header */ @@ -1414,25 +1423,22 @@ OverviewPage PrivateSend QWidget .QFrame#framePrivateSend { /* PrivateSend Widget */ background-color: #00000000; max-width: 451px; - min-width: 451px; max-height: 350px; } QWidget .QFrame#framePrivateSend > .QLabel { - min-width: 175px; + min-width: 100px; min-height: 26px; } QWidget .QFrame#framePrivateSend .QLabel#labelPrivateSendHeader { /* PrivateSend Header */ qproperty-alignment: 'AlignVCenter | AlignLeft'; - margin-right: 10px; + margin-right: 5px; } QWidget .QFrame#framePrivateSend .QLabel#labelPrivateSendSyncStatus { /* PrivateSend Sync Status */ qproperty-alignment: 'AlignVCenter | AlignLeft'; color: #a84832; - margin-left: 2px; - padding-right: 5px; } QWidget .QFrame#framePrivateSend .QLabel#labelPrivateSendEnabledText { /* PrivateSend Enabled Status Label */ @@ -1510,35 +1516,23 @@ OverviewPage RecentTransactions ******************************************************/ QWidget .QFrame#frame_2 { /* Transactions Widget */ - min-width: 510px; - margin-right: 20px; - margin-left: 0; - margin-top: 0; + min-width: 430; } QWidget .QFrame#frame_2 .QLabel#label_4 { /* Recent Transactions Label */ - min-width: 180px; - margin-left: 18px; - margin-top: 0; - margin-right: 5px; - padding-right: 5px; + margin-right: 0px; min-height: 30px; } QWidget .QFrame#frame_2 .QLabel#labelTransactionsStatus { /* Recent Transactions Sync Status */ - qproperty-alignment: 'AlignBottom | AlignRight'; + qproperty-alignment: 'AlignVCenter | AlignLeft'; color: #a84832; - min-width: 93px; - margin-top: 0; - margin-left: 16px; - margin-right: 5px; - min-height: 16px; } QWidget .QFrame#frame_2 QListView { /* Transaction List */ - max-width: 369px; - margin-top: 12px; - margin-left: 0px; /* CSS Voodoo - set to -66px to hide default transaction icons */ + background: #00000000; + max-width: 430px; + margin-right: 10px; } /****************************************************** diff --git a/src/qt/res/css/traditional.css b/src/qt/res/css/traditional.css index cbb42a5ebb..dc297193e6 100644 --- a/src/qt/res/css/traditional.css +++ b/src/qt/res/css/traditional.css @@ -20,6 +20,7 @@ Loaded in GUIUtil::loadStyleSheet() in guitil.cpp. # Used colors in traditional.css for commit 44de8a93f2 #00000000 +#222222 #333 #fff #008de4 @@ -226,12 +227,25 @@ QDialog#OptionsDialog QLabel#overriddenByCommandLineInfoLabel { OverviewPage ******************************************************/ +QWidget#OverviewPage QLabel#labelAlerts { + background-color: #c79304; + color: #222222; + border-radius: 5px; + padding: 5px; + } + QWidget .QFrame#frame .QLabel#labelWalletStatus, /* Wallet Sync Status */ QWidget .QFrame#framePrivateSend .QLabel#labelPrivateSendSyncStatus, /* PrivateSend Sync Status */ QWidget .QFrame#frame_2 .QLabel#labelTransactionsStatus { /* Recent Transactions Sync Status */ color: #a84832; } +QWidget .QFrame#frame_2 QListView { /* Transaction List */ + background: #00000000; + min-width: 430px; + margin-right: 10px; +} + /****************************************************** SendCoinsDialog ******************************************************/ diff --git a/src/qt/transactionfilterproxy.cpp b/src/qt/transactionfilterproxy.cpp index aae39bb69c..58fbfbdfec 100644 --- a/src/qt/transactionfilterproxy.cpp +++ b/src/qt/transactionfilterproxy.cpp @@ -98,7 +98,9 @@ void TransactionFilterProxy::setWatchOnlyFilter(WatchOnlyFilter filter) void TransactionFilterProxy::setLimit(int limit) { + Q_EMIT layoutAboutToBeChanged(); this->limitRows = limit; + Q_EMIT layoutChanged(); } void TransactionFilterProxy::setShowInactive(bool _showInactive)