Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gui: Fix macOS display inconsistencies #2106

Merged
merged 9 commits into from
Apr 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion src/Makefile.qt.include
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ GRIDCOINRESEARCH_QT_H = \
qt/coincontroldialog.h \
qt/coincontroltreewidget.h \
qt/csvmodelwriter.h \
qt/decoration.h \
qt/diagnosticsdialog.h \
qt/editaddressdialog.h \
qt/guiconstants.h \
Expand Down Expand Up @@ -243,6 +244,7 @@ GRIDCOINRESEARCH_QT_CPP = \
qt/coincontroldialog.cpp \
qt/coincontroltreewidget.cpp \
qt/csvmodelwriter.cpp \
qt/decoration.cpp \
qt/diagnosticsdialog.cpp \
qt/editaddressdialog.cpp \
qt/guiutil.cpp \
Expand Down Expand Up @@ -435,7 +437,9 @@ RES_IMAGES = \

RES_FONTS = \
qt/res/fonts/Inconsolata-Regular.ttf \
qt/res/fonts/Inter-VariableFont.ttf
qt/res/fonts/Inter-Bold.otf \
qt/res/fonts/Inter-Medium.otf \
qt/res/fonts/Inter-Regular.otf

RES_STYLESHEETS = \
qt/res/stylesheets/light_stylesheet.qss \
Expand Down
4 changes: 3 additions & 1 deletion src/qt/bitcoin.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,9 @@
</qresource>
<qresource prefix="/fonts">
<file alias="inconsolata-regular">res/fonts/Inconsolata-Regular.ttf</file>
<file alias="inter-variable">res/fonts/Inter-VariableFont.ttf</file>
<file alias="inter-bold">res/fonts/Inter-Bold.otf</file>
<file alias="inter-medium">res/fonts/Inter-Medium.otf</file>
<file alias="inter-regular">res/fonts/Inter-Regular.otf</file>
</qresource>
<qresource prefix="/movies"/>
<qresource prefix="/stylesheets">
Expand Down
1 change: 1 addition & 0 deletions src/qt/bitcoinamountfield.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ BitcoinAmountField::BitcoinAmountField(QWidget *parent):
layout->addWidget(amount);
unit = new QValueComboBox(this);
unit->setModel(new BitcoinUnits(this));
unit->setMinimumWidth(80);
layout->addWidget(unit);
layout->addStretch(1);
layout->setContentsMargins(0,0,0,0);
Expand Down
61 changes: 33 additions & 28 deletions src/qt/bitcoingui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <QProcess>
#include <QInputDialog>

#include "qt/decoration.h"
#include "bitcoingui.h"
#include "transactiontablemodel.h"
#include "addressbookpage.h"
Expand Down Expand Up @@ -109,19 +110,25 @@ BitcoinGUI::BitcoinGUI(QWidget *parent):
* 0.4,QDesktopWidget().availableGeometry(this)));
}

QFontDatabase::addApplicationFont(":/fonts/inter-variable");
QFontDatabase::addApplicationFont(":/fonts/inter-bold");
QFontDatabase::addApplicationFont(":/fonts/inter-medium");
QFontDatabase::addApplicationFont(":/fonts/inter-regular");
QFontDatabase::addApplicationFont(":/fonts/inconsolata-regular");

#ifndef Q_OS_MAC
// This slightly enlarges the application's base font size on Windows and
// Linux. MacOS often uses a different reference DPI so this can actually
// cause the rendered text to appear smaller. On Mac, the default size is
// adequate.
// Linux. MacOS often uses a different reference DPI so the size used for
// Windows and Linux causes the rendered text to appear smaller. For Mac,
// we set an explicit application-wide font size to Qt's default value to
// normalize text size on controls like toolbar buttons and tabs that can
// render smaller with the Cocoa integration plugin:
//
QFont appFont = qApp->font();
#ifndef Q_OS_MAC
appFont.setPointSize(10);
qApp->setFont(appFont);
#else
appFont.setPointSize(13);
#endif
qApp->setFont(appFont);

// Qt paints some decorations directly and provides no stylesheet hooks to
// customize appearance (for example: the rulers in a QWizardPage). We set
Expand Down Expand Up @@ -437,7 +444,7 @@ void BitcoinGUI::createActions()
void BitcoinGUI::setIcons()
{
const QToolBar* toolbar = findChild<QToolBar*>();
const int toolbar_icon_size = 16 * logicalDpiX() / 96;
const int toolbar_icon_size = GRC::ScalePx(this, 16);

ToolbarButtonIconFilter::apply(
this,
Expand Down Expand Up @@ -590,7 +597,7 @@ void BitcoinGUI::createToolBars()
toolbar->setContextMenuPolicy(Qt::PreventContextMenu);
// Setting a taller height than the rendered icon provides additional
// padding between the icon and the button text:
toolbar->setIconSize(QSize(16 * logicalDpiX() / 96, 24 * logicalDpiX() / 96));
toolbar->setIconSize(GRC::ScaleSize(this, 16, 24));
toolbar->addWidget(logoLabel);
toolbar->addAction(overviewAction);
toolbar->addAction(sendCoinsAction);
Expand Down Expand Up @@ -620,7 +627,6 @@ void BitcoinGUI::createToolBars()
}

frameBlocks->setContentsMargins(0,0,0,0);
frameBlocks->setMinimumHeight(STATUSBAR_ICONSIZE);

QHBoxLayout *frameBlocksLayout = new QHBoxLayout(frameBlocks);
frameBlocks->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
Expand Down Expand Up @@ -652,7 +658,7 @@ void BitcoinGUI::createToolBars()
timerStakingIcon->start(MODEL_UPDATE_DELAY);
// Instead of calling updateStakingIcon here, simply set the icon to staking off.
// This is to prevent problems since this GUI code can initialize before the core.
labelStakingIcon->setPixmap(QIcon(":/icons/status_staking_no_" + sSheet).pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
labelStakingIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_staking_no_" + sSheet));
labelStakingIcon->setToolTip(tr("Not staking: Miner is not initialized."));
}

Expand Down Expand Up @@ -883,7 +889,7 @@ void BitcoinGUI::setNumConnections(int n)
}

icon.append("_").append(sSheet);
labelConnectionsIcon->setPixmap(QIcon(icon).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelConnectionsIcon->setPixmap(GRC::ScaleStatusIcon(this, icon));

if (n == 0)
{
Expand All @@ -903,7 +909,7 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
// return if we have no connection to the network
if (!clientModel || clientModel->getNumConnections() == 0)
{
labelBlocksIcon->setPixmap(QIcon(":/icons/status_sync_stalled_" + sSheet).pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
labelBlocksIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_sync_stalled_" + sSheet));
labelBlocksIcon->setToolTip(tr("Sync: no connections."));
return;
}
Expand Down Expand Up @@ -941,13 +947,13 @@ void BitcoinGUI::setNumBlocks(int count, int nTotalBlocks)
if(secs < 90*60 && count >= nTotalBlocks)
{
tooltip = tr("Up to date") + QString(".<br>") + tooltip;
labelBlocksIcon->setPixmap(QIcon(":/icons/status_sync_done_" + sSheet).pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
labelBlocksIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_sync_done_" + sSheet));

overviewPage->showOutOfSyncWarning(false);
}
else
{
labelBlocksIcon->setPixmap(QIcon(":/icons/status_sync_syncing_" + sSheet).pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
labelBlocksIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_sync_syncing_" + sSheet));
tooltip = tr("Catching up...") + QString("<br>") + tooltip;

overviewPage->showOutOfSyncWarning(true);
Expand Down Expand Up @@ -1326,7 +1332,7 @@ void BitcoinGUI::setEncryptionStatus(int status)
switch(status)
{
case WalletModel::Unencrypted:
labelEncryptionIcon->setPixmap(QIcon(":/icons/status_encryption_none_" + sSheet).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelEncryptionIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_encryption_none_" + sSheet));
labelEncryptionIcon->setToolTip(tr("Wallet is <b>not encrypted</b>!"));
encryptWalletAction->setChecked(false);
changePassphraseAction->setEnabled(false);
Expand All @@ -1336,9 +1342,9 @@ void BitcoinGUI::setEncryptionStatus(int status)
break;
case WalletModel::Unlocked:
if (fWalletUnlockStakingOnly) {
labelEncryptionIcon->setPixmap(QIcon(":/icons/status_encryption_unlocked_" + sSheet).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelEncryptionIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_encryption_unlocked_" + sSheet));
} else {
labelEncryptionIcon->setPixmap(QIcon(":/icons/status_encryption_none_" + sSheet).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelEncryptionIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_encryption_none_" + sSheet));
}
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently %1 ").arg(fWalletUnlockStakingOnly ? tr("<b>unlocked for staking only</b>") : tr("<b>fully unlocked</b>")));
encryptWalletAction->setChecked(true);
Expand All @@ -1348,7 +1354,7 @@ void BitcoinGUI::setEncryptionStatus(int status)
encryptWalletAction->setEnabled(false); // TODO: decrypt currently not supported
break;
case WalletModel::Locked:
labelEncryptionIcon->setPixmap(QIcon(":/icons/status_encryption_locked_" + sSheet).pixmap(STATUSBAR_ICONSIZE,STATUSBAR_ICONSIZE));
labelEncryptionIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_encryption_locked_" + sSheet));
labelEncryptionIcon->setToolTip(tr("Wallet is <b>encrypted</b> and currently <b>locked</b>"));
encryptWalletAction->setChecked(true);
changePassphraseAction->setEnabled(true);
Expand Down Expand Up @@ -1533,7 +1539,7 @@ void BitcoinGUI::updateStakingIcon()

if (globalStatus.staking)
{
labelStakingIcon->setPixmap(QIcon(":/icons/status_staking_yes_" + sSheet).pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
labelStakingIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_staking_yes_" + sSheet));
labelStakingIcon->setToolTip(tr("Staking.<br>Your weight is %1<br>Network weight is %2<br><b>Estimated</b> staking frequency is %3.")
.arg(QString::number(globalStatus.coinWeight, 'f', 0))
.arg(QString::number(globalStatus.netWeight, 'f', 0))
Expand All @@ -1550,7 +1556,7 @@ void BitcoinGUI::updateStakingIcon()
}
else if (!globalStatus.staking && !globalStatus.able_to_stake)
{
labelStakingIcon->setPixmap(QIcon(":/icons/status_staking_problem_" + sSheet).pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
labelStakingIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_staking_problem_" + sSheet));
//Part of this string won't be translated :(
labelStakingIcon->setToolTip(tr("Unable to stake: %1")
.arg(QString(globalStatus.ReasonNotStaking.c_str())));
Expand All @@ -1566,7 +1572,7 @@ void BitcoinGUI::updateStakingIcon()
}
else
{
labelStakingIcon->setPixmap(QIcon(":/icons/status_staking_no_" + sSheet).pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
labelStakingIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_staking_no_" + sSheet));
//Part of this string won't be translated :(
labelStakingIcon->setToolTip(tr("Not staking currently: %1, <b>Estimated</b> staking frequency is %2.")
.arg(QString(globalStatus.ReasonNotStaking.c_str()))
Expand Down Expand Up @@ -1641,23 +1647,23 @@ void BitcoinGUI::updateScraperIcon(int scraperEventtype, int status)

if (scraperEventtype == (int)scrapereventtypes::OutOfSync && status == CT_UPDATING)
{
labelScraperIcon->setPixmap(QIcon(":/icons/status_scraper_waiting_" + sSheet).pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
labelScraperIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_scraper_waiting_" + sSheet));
labelScraperIcon->setToolTip(tr("Scraper: waiting on wallet to sync."));
}
else if (scraperEventtype == (int)scrapereventtypes::Sleep && status == CT_NEW)
{
labelScraperIcon->setPixmap(QIcon(":/icons/status_scraper_inactive_" + sSheet).pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
labelScraperIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_scraper_inactive_" + sSheet));
labelScraperIcon->setToolTip(tr("Scraper: superblock not needed - inactive."));
}
else if (scraperEventtype == (int)scrapereventtypes::Stats && (status == CT_NEW || status == CT_UPDATED || status == CT_UPDATING))
{
labelScraperIcon->setPixmap(QIcon(":/icons/status_scraper_waiting_" + sSheet).pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
labelScraperIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_scraper_waiting_" + sSheet));
labelScraperIcon->setToolTip(tr("Scraper: downloading and processing stats."));
}
else if ((scraperEventtype == (int)scrapereventtypes::Convergence || scraperEventtype == (int)scrapereventtypes::SBContract)
&& (status == CT_NEW || status == CT_UPDATED) && nConvergenceTime)
{
labelScraperIcon->setPixmap(QIcon(":/icons/status_scraper_ok_" + sSheet).pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
labelScraperIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_scraper_ok_" + sSheet));

if (bDisplayScrapers)
{
Expand All @@ -1683,7 +1689,7 @@ void BitcoinGUI::updateScraperIcon(int scraperEventtype, int status)
else if ((scraperEventtype == (int)scrapereventtypes::Convergence || scraperEventtype == (int)scrapereventtypes::SBContract)
&& status == CT_DELETED)
{
labelScraperIcon->setPixmap(QIcon(":/icons/status_scraper_no_convergence_" + sSheet).pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
labelScraperIcon->setPixmap(GRC::ScaleStatusIcon(this, ":/icons/status_scraper_no_convergence_" + sSheet));
labelScraperIcon->setToolTip(tr("Scraper: No convergence able to be achieved. Will retry in a few minutes."));
}

Expand All @@ -1701,8 +1707,7 @@ void BitcoinGUI::updateBeaconIcon()
}

labelBeaconIcon->show();
labelBeaconIcon->setPixmap(researcherModel->getBeaconStatusIcon()
.pixmap(STATUSBAR_ICONSIZE, STATUSBAR_ICONSIZE));
labelBeaconIcon->setPixmap(GRC::ScaleStatusIcon(this, researcherModel->getBeaconStatusIcon()));

labelBeaconIcon->setToolTip(tr(
"CPID: %1\n"
Expand Down
2 changes: 0 additions & 2 deletions src/qt/bitcoingui.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,6 @@ class BitcoinGUI : public QMainWindow
// name extension to change icons according to stylesheet
QString sSheet;

int STATUSBAR_ICONSIZE = UNSCALED_STATUSBAR_ICONSIZE * logicalDpiX() / 96;

/** Create the main UI actions. */
void createActions();
/** Create the menu bar and sub-menus. */
Expand Down
106 changes: 106 additions & 0 deletions src/qt/decoration.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright (c) 2014-2021 The Gridcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/decoration.h>

#include <QFont>
#include <QIcon>
#include <QPaintDevice>
#include <QPixmap>
#include <QSize>
#include <QWidget>

using namespace GRC;

namespace {
//!
//! \brief The pixels-per-inch value that the user interface is designed for.
//!
constexpr int REFERENCE_DPI = 96;

//!
//! \brief The virtual pixels-per-inch of the operating system.
//!
//! MacOS typically uses a different base DPI than Windows or Linux. This
//! causes rendering calculated from a reference DPI to appear smaller on
//! Macs which creates legibility and layout issues.
//!
#ifdef Q_OS_MAC
constexpr int OS_BASE_DPI = 72;
#else
constexpr int OS_BASE_DPI = 96;
#endif

//!
//! \brief The base width and height in pixels for status bar icons.
//!
constexpr int STATUSBAR_ICONSIZE = 16;
} // Anonymous namespace

// -----------------------------------------------------------------------------
// Functions
// -----------------------------------------------------------------------------

void GRC::ScaleFontPointSize(QWidget* widget, int point_size)
{
if (!widget) {
return;
}

QFont font = widget->font();
font.setPointSize(point_size * REFERENCE_DPI / OS_BASE_DPI);
widget->setFont(font);
}

void GRC::ScaleFontPointSizeF(QWidget* widget, double point_size)
{
if (!widget) {
return;
}

QFont font = widget->font();
font.setPointSizeF(point_size * REFERENCE_DPI / OS_BASE_DPI);
widget->setFont(font);
}

int GRC::ScalePx(QPaintDevice* painter, int px)
{
if (!painter) {
return px;
}

return painter->logicalDpiX() * px / OS_BASE_DPI;
}

QSize GRC::ScaleSize(QPaintDevice* painter, int width, int height)
{
return QSize(ScalePx(painter, width), ScalePx(painter, height));
}

QSize GRC::ScaleSize(QPaintDevice* painter, int size)
{
return ScaleSize(painter, size, size);
}

QPixmap GRC::ScaleIcon(QPaintDevice* painter, const QIcon& icon, int size)
{
const int scaled_size = ScalePx(painter, size);

return icon.pixmap(scaled_size, scaled_size);
}

QPixmap GRC::ScaleIcon(QPaintDevice* painter, const QString& icon_path, int size)
{
return ScaleIcon(painter, QIcon(icon_path), size);
}

QPixmap GRC::ScaleStatusIcon(QPaintDevice* painter, const QIcon& icon)
{
return ScaleIcon(painter, icon, STATUSBAR_ICONSIZE);
}

QPixmap GRC::ScaleStatusIcon(QPaintDevice* painter, const QString& icon_path)
{
return ScaleIcon(painter, icon_path, STATUSBAR_ICONSIZE);
}
Loading