diff --git a/src/dialog/txconfadvdialog.cpp b/src/dialog/txconfadvdialog.cpp index 80a48ca..507334e 100644 --- a/src/dialog/txconfadvdialog.cpp +++ b/src/dialog/txconfadvdialog.cpp @@ -8,6 +8,7 @@ #include "libwalletqt/Transfer.h" #include "libwalletqt/Input.h" #include "model/ModelUtils.h" +#include "utils/ColorScheme.h" #include #include @@ -52,7 +53,7 @@ void TxConfAdvDialog::setTransaction(PendingTransaction *tx) { m_tx = tx; m_tx->refresh(); - PendingTransactionInfo *ptx = m_tx->transaction(0); + PendingTransactionInfo *ptx = m_tx->transaction(0); //Todo: support split transactions ui->txid->setText(tx->txid().first()); @@ -102,12 +103,16 @@ void TxConfAdvDialog::setupConstructionData(ConstructionInfo *ci) { ui->inputs->setText(inputs_str); ui->label_inputs->setText(QString("Inputs (%1)").arg(QString::number(inputs.size()))); - QString outputs_str; auto outputs = ci->outputs(); + + QTextCursor cursor = ui->outputs->textCursor(); for (const auto& o: outputs) { - outputs_str += QString("%1 %2\n").arg(o->address(), WalletManager::displayAmount(o->amount())); + auto address = o->address(); + auto amount = WalletManager::displayAmount(o->amount()); + cursor.insertText(address, textFormat(address)); + cursor.insertText(QString(" %1").arg(amount), QTextCharFormat()); + cursor.insertBlock(); } - ui->outputs->setText(outputs_str); ui->label_outputs->setText(QString("Outputs (%1)").arg(QString::number(outputs.size()))); ui->label_ringSize->setText(QString("Ring size: %1").arg(QString::number(ci->minMixinCount() + 1))); @@ -178,6 +183,23 @@ void TxConfAdvDialog::closeDialog() { QDialog::reject(); } +QTextCharFormat TxConfAdvDialog::textFormat(const QString &address) { + auto index = m_ctx->currentWallet->subaddressIndex(address); + if (index.first == 0 && index.second == 0) { + QTextCharFormat rec; + rec.setBackground(QBrush(ColorScheme::YELLOW.asColor(true))); + rec.setToolTip("Wallet change/primary address"); + return rec; + } + if (index.first >= 0) { + QTextCharFormat rec; + rec.setBackground(QBrush(ColorScheme::GREEN.asColor(true))); + rec.setToolTip("Wallet receive address"); + return rec; + } + return QTextCharFormat(); +} + TxConfAdvDialog::~TxConfAdvDialog() { delete ui; } diff --git a/src/dialog/txconfadvdialog.h b/src/dialog/txconfadvdialog.h index 311e4b8..6d426e7 100644 --- a/src/dialog/txconfadvdialog.h +++ b/src/dialog/txconfadvdialog.h @@ -8,6 +8,7 @@ #include #include #include +#include #include "libwalletqt/PendingTransaction.h" #include "appcontext.h" @@ -41,6 +42,8 @@ private: void signedQrCode(); void signedSaveFile(); + QTextCharFormat textFormat(const QString &address); + Ui::TxConfAdvDialog *ui; AppContext *m_ctx; PendingTransaction *m_tx = nullptr; diff --git a/src/dialog/txconfdialog.cpp b/src/dialog/txconfdialog.cpp index b088c5d..4922724 100644 --- a/src/dialog/txconfdialog.cpp +++ b/src/dialog/txconfdialog.cpp @@ -6,6 +6,7 @@ #include "model/ModelUtils.h" #include "txconfadvdialog.h" #include "globals.h" +#include "utils/ColorScheme.h" #include @@ -42,20 +43,32 @@ TxConfDialog::TxConfDialog(AppContext *ctx, PendingTransaction *tx, const QStrin int maxLengthFiat = Utils::maxLength(amounts_fiat); std::for_each(amounts_fiat.begin(), amounts_fiat.end(), [maxLengthFiat](QString& amount){amount = amount.rightJustified(maxLengthFiat, ' ');}); + ui->label_amount->setFont(ModelUtils::getMonospaceFont()); + ui->label_fee->setFont(ModelUtils::getMonospaceFont()); + ui->label_total->setFont(ModelUtils::getMonospaceFont()); + ui->label_amount->setText(QString("%1 (%2 %3)").arg(amounts[0], amounts_fiat[0], preferredCur)); ui->label_fee->setText(QString("%1 (%2 %3)").arg(amounts[1], amounts_fiat[1], preferredCur)); ui->label_total->setText(QString("%1 (%2 %3)").arg(amounts[2], amounts_fiat[2], preferredCur)); auto subaddressIndex = m_ctx->currentWallet->subaddressIndex(address); QString addressExtra; + + ui->label_address->setText(ModelUtils::displayAddress(address, 2)); + ui->label_address->setFont(ModelUtils::getMonospaceFont()); + ui->label_address->setToolTip(address); + if (subaddressIndex.first >= 0) { ui->label_note->setText("Note: this is a churn transaction."); ui->label_note->show(); + ui->label_address->setStyleSheet(ColorScheme::GREEN.asStylesheet(true)); + ui->label_address->setToolTip("Wallet receive address"); } - ui->label_address->setText(ModelUtils::displayAddress(address, 2)); - ui->label_address->setFont(ModelUtils::getMonospaceFont()); - ui->label_address->setToolTip(address); + if (subaddressIndex.first == 0 && subaddressIndex.second == 0) { + ui->label_address->setStyleSheet(ColorScheme::YELLOW.asStylesheet(true)); + ui->label_address->setToolTip("Wallet change/primary address"); + } ui->buttonBox->button(QDialogButtonBox::Ok)->setText("Send"); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index fea615c..0124f79 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -22,6 +22,7 @@ #include "dialog/WalletCacheDebugDialog.h" #include "ui_mainwindow.h" #include "globals.h" +#include "utils/ColorScheme.h" // libwalletqt #include "libwalletqt/AddressBook.h" @@ -365,6 +366,7 @@ MainWindow::MainWindow(AppContext *ctx, QWidget *parent) : this->initMenu(); connect(&m_updateBytes, &QTimer::timeout, this, &MainWindow::updateNetStats); + ColorScheme::updateFromWidget(this); } void MainWindow::initMain() { @@ -1041,6 +1043,7 @@ void MainWindow::skinChanged(const QString &skinName) { config()->set(Config::skin, skinName); qApp->setStyleSheet(m_skins[skinName]); qDebug() << QString("Skin changed to %1").arg(skinName); + ColorScheme::updateFromWidget(this); } void MainWindow::closeEvent(QCloseEvent *event) { diff --git a/src/model/CoinsModel.cpp b/src/model/CoinsModel.cpp index 3e51c6b..9231695 100644 --- a/src/model/CoinsModel.cpp +++ b/src/model/CoinsModel.cpp @@ -6,6 +6,7 @@ #include "Coins.h" #include "ModelUtils.h" #include "globals.h" +#include "utils/ColorScheme.h" #include #include @@ -67,13 +68,13 @@ QVariant CoinsModel::data(const QModelIndex &index, int role) const } else if (role == Qt::BackgroundRole) { if (cInfo.spent()) { - result = QBrush(QColor(255, 100, 100)); + result = QBrush(ColorScheme::RED.asColor(true)); } else if (cInfo.frozen()) { - result = QBrush(QColor(173, 216, 230)); + result = QBrush(ColorScheme::BLUE.asColor(true)); } else if (!cInfo.unlocked()) { - result = QBrush(QColor("#60993E")); + result = QBrush(ColorScheme::YELLOW.asColor(true)); } } else if (role == Qt::TextAlignmentRole) { diff --git a/src/model/NodeModel.cpp b/src/model/NodeModel.cpp index ec97e8c..fabbbc1 100644 --- a/src/model/NodeModel.cpp +++ b/src/model/NodeModel.cpp @@ -2,7 +2,8 @@ // Copyright (c) 2020-2021, The Monero Project. #include "NodeModel.h" -#include +#include "utils/nodes.h" +#include "utils/ColorScheme.h" NodeModel::NodeModel(int nodeSource, QObject *parent) : QAbstractTableModel(parent) @@ -69,9 +70,9 @@ QVariant NodeModel::data(const QModelIndex &index, int role) const { } else if(role == Qt::BackgroundRole) { if (node.isConnecting) - return QBrush(QColor("#A9DEF9")); + return QBrush(ColorScheme::YELLOW.asColor(true)); else if (node.isActive) - return QBrush(QColor("#78BC61")); + return QBrush(ColorScheme::GREEN.asColor(true)); } return QVariant(); } diff --git a/src/model/SubaddressModel.cpp b/src/model/SubaddressModel.cpp index 15a6e62..35ea020 100644 --- a/src/model/SubaddressModel.cpp +++ b/src/model/SubaddressModel.cpp @@ -4,6 +4,7 @@ #include "SubaddressModel.h" #include "Subaddress.h" #include "ModelUtils.h" +#include "utils/ColorScheme.h" #include #include @@ -56,8 +57,13 @@ QVariant SubaddressModel::data(const QModelIndex &index, int role) const result = parseSubaddressRow(subaddress, index, role); } else if (role == Qt::BackgroundRole) { - if (subaddress.isUsed()) { - result = QBrush(QColor(255,100,100)); + switch(index.column()) { + case Address: + { + if (subaddress.isUsed()) { + result = QBrush(ColorScheme::RED.asColor(true)); + } + } } } else if (role == Qt::FontRole) { @@ -68,6 +74,16 @@ QVariant SubaddressModel::data(const QModelIndex &index, int role) const } } } + else if (role == Qt::ToolTipRole) { + switch(index.column()) { + case Address: + { + if (subaddress.isUsed()) { + result = "This address is used."; + } + } + } + } }); if (!found) diff --git a/src/model/TransactionHistoryModel.cpp b/src/model/TransactionHistoryModel.cpp index 35b127c..0c96526 100644 --- a/src/model/TransactionHistoryModel.cpp +++ b/src/model/TransactionHistoryModel.cpp @@ -5,6 +5,7 @@ #include "TransactionHistory.h" #include "TransactionInfo.h" #include "globals.h" +#include "utils/ColorScheme.h" TransactionHistoryModel::TransactionHistoryModel(QObject *parent) : QAbstractTableModel(parent), diff --git a/src/model/XmrToModel.cpp b/src/model/XmrToModel.cpp index ebe4efb..f6f4a2d 100644 --- a/src/model/XmrToModel.cpp +++ b/src/model/XmrToModel.cpp @@ -4,6 +4,7 @@ #include "XmrToModel.h" #include "model/ModelUtils.h" #include "utils/xmrto.h" +#include "utils/ColorScheme.h" XmrToModel::XmrToModel(QList *orders, QObject *parent) : QAbstractTableModel(parent), @@ -61,15 +62,15 @@ QVariant XmrToModel::data(const QModelIndex &index, int role) const { else if(role == Qt::BackgroundRole) { if (_col == 0) { if (order->state == OrderState::Status_OrderPaid || order->state == OrderState::Status_OrderPaidUnconfirmed) - return QBrush(Qt::darkGreen); + return QBrush(ColorScheme::GREEN.asColor(true)); else if (order->state == OrderState::Status_OrderCreating || order->state == OrderState::Status_OrderToBeCreated) - return QBrush(Qt::yellow); + return QBrush(ColorScheme::YELLOW.asColor(true)); else if (order->state == OrderState::Status_OrderUnpaid) - return QBrush(Qt::cyan); + return QBrush(ColorScheme::YELLOW.asColor(true)); else if (order->state == OrderState::Status_OrderBTCSent) - return QBrush(Qt::green); + return QBrush(ColorScheme::GREEN.asColor(true)); else if (order->state == OrderState::Status_OrderFailed || order->state == OrderState::Status_OrderTimedOut) - return QBrush(QColor(191, 255, 0)); // lime + return QBrush(ColorScheme::RED.asColor(true)); } } else if (role == Qt::FontRole) { diff --git a/src/utils/ColorScheme.cpp b/src/utils/ColorScheme.cpp new file mode 100644 index 0000000..be4555a --- /dev/null +++ b/src/utils/ColorScheme.cpp @@ -0,0 +1,39 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. +// Copyright (c) 2012 thomasv@gitorious + +#include "ColorScheme.h" + +bool ColorScheme::darkScheme = false; +ColorSchemeItem ColorScheme::GREEN = ColorSchemeItem("#117c11", "#8af296"); +ColorSchemeItem ColorScheme::YELLOW = ColorSchemeItem("#897b2a", "#ffff00"); +ColorSchemeItem ColorScheme::RED = ColorSchemeItem("#7c1111", "#f18c8c"); +ColorSchemeItem ColorScheme::BLUE = ColorSchemeItem("#123b7c", "#8cb3f2"); +ColorSchemeItem ColorScheme::DEFAULT = ColorSchemeItem("black", "white"); +ColorSchemeItem ColorScheme::GRAY = ColorSchemeItem("gray", "gray"); + +bool ColorScheme::hasDarkBackground(QWidget *widget) { + int r, g, b; + widget->palette().color(QPalette::Background).getRgb(&r, &g, &b); + auto brightness = r + g + b; + return brightness < (255*3/2); +} + +void ColorScheme::updateFromWidget(QWidget *widget, bool forceDark) { + darkScheme = forceDark or ColorScheme::hasDarkBackground(widget); +} + +QString ColorSchemeItem::asStylesheet(bool background) { + auto cssPrefix = background ? "background-" : ""; + auto color = this->getColor(background); + return QString("QWidget { %1color : %2; }").arg(cssPrefix, color); +} + +QColor ColorSchemeItem::asColor(bool background) { + auto color = this->getColor(background); + return QColor(color); +} + +QString ColorSchemeItem::getColor(bool background) { + return m_colors[(int(background) + int(ColorScheme::darkScheme)) % 2]; +} \ No newline at end of file diff --git a/src/utils/ColorScheme.h b/src/utils/ColorScheme.h new file mode 100644 index 0000000..9037271 --- /dev/null +++ b/src/utils/ColorScheme.h @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2020-2021, The Monero Project. +// Copyright (c) 2012 thomasv@gitorious + +#ifndef FEATHER_COLORSCHEME_H +#define FEATHER_COLORSCHEME_H + +#include +#include +#include +#include + +class ColorSchemeItem { + +public: + explicit ColorSchemeItem(const QString &fgColor, const QString &bgColor) + : m_colors({fgColor, bgColor}) {} + + QString asStylesheet(bool background = false); + QColor asColor(bool background = false); + +private: + QString getColor(bool background); + QVector m_colors; +}; + + +class ColorScheme { +public: + static bool darkScheme; + + static ColorSchemeItem GREEN; + static ColorSchemeItem YELLOW; + static ColorSchemeItem RED; + static ColorSchemeItem BLUE; + static ColorSchemeItem DEFAULT; + static ColorSchemeItem GRAY; + + static bool hasDarkBackground(QWidget *widget); + static void updateFromWidget(QWidget *widget, bool forceDark = false); +}; + + +#endif //FEATHER_COLORSCHEME_H