From 388811296e68faaead171b3002ca4ec673cdb13b Mon Sep 17 00:00:00 2001 From: SomberNight Date: Wed, 10 Aug 2022 19:53:36 +0200 Subject: [PATCH] qt: replace some hardcoded pixel sizes for better high-dpi support --- electrum/gui/qt/balance_dialog.py | 26 +++++++++++++------------- electrum/gui/qt/channels_list.py | 13 +++++++------ electrum/gui/qt/console.py | 4 ++-- electrum/gui/qt/exception_window.py | 4 ++-- electrum/gui/qt/installwizard.py | 4 ++-- electrum/gui/qt/lightning_tx_dialog.py | 4 ++-- electrum/gui/qt/main_window.py | 16 ++++++++++------ electrum/gui/qt/new_channel_dialog.py | 26 ++++++++++++++++++-------- electrum/gui/qt/seed_dialog.py | 4 ++-- electrum/gui/qt/send_tab.py | 5 +++-- electrum/gui/qt/swap_dialog.py | 5 +++-- electrum/gui/qt/util.py | 9 +++++++-- electrum/gui/qt/watchtower_dialog.py | 2 +- electrum/plugins/virtualkeyboard/qt.py | 13 +++++++++---- 14 files changed, 81 insertions(+), 54 deletions(-) diff --git a/electrum/gui/qt/balance_dialog.py b/electrum/gui/qt/balance_dialog.py index f447bc4ee..1b187e22f 100644 --- a/electrum/gui/qt/balance_dialog.py +++ b/electrum/gui/qt/balance_dialog.py @@ -25,19 +25,16 @@ from typing import TYPE_CHECKING -from PyQt5.QtCore import Qt -from PyQt5.QtGui import QPixmap from PyQt5.QtWidgets import (QVBoxLayout, QCheckBox, QHBoxLayout, QLineEdit, QLabel, QCompleter, QDialog, QStyledItemDelegate, QScrollArea, QWidget, QPushButton, QGridLayout, QToolButton) - from PyQt5.QtCore import QRect, QEventLoop, Qt, pyqtSignal from PyQt5.QtGui import QPalette, QPen, QPainter, QPixmap from electrum.i18n import _ -from .util import Buttons, CloseButton, WindowModalDialog, ColorScheme +from .util import Buttons, CloseButton, WindowModalDialog, ColorScheme, font_height if TYPE_CHECKING: from .main_window import ElectrumWindow @@ -100,7 +97,7 @@ class BalanceToolButton(QToolButton, PieChartObject): def __init__(self): QToolButton.__init__(self) - self.size = 18 + self.size = max(18, font_height()) self._list = [] self.R = QRect(6, 3, self.size, self.size) @@ -167,14 +164,17 @@ class BalanceDialog(WindowModalDialog): lightning_fiat_str = self.fx.format_amount_and_units(lightning) if self.fx else '' f_lightning_fiat_str = self.fx.format_amount_and_units(f_lightning) if self.fx else '' - piechart = PieChartWidget(120, [ - (_('Frozen'), COLOR_FROZEN, frozen), - (_('Unmatured'), COLOR_UNMATURED, unmatured), - (_('Unconfirmed'), COLOR_UNCONFIRMED, unconfirmed), - (_('On-chain'), COLOR_CONFIRMED, confirmed), - (_('Lightning'), COLOR_LIGHTNING, lightning), - (_('Lightning frozen'), COLOR_FROZEN_LIGHTNING, f_lightning), - ]) + piechart = PieChartWidget( + max(120, 9 * font_height()), + [ + (_('Frozen'), COLOR_FROZEN, frozen), + (_('Unmatured'), COLOR_UNMATURED, unmatured), + (_('Unconfirmed'), COLOR_UNCONFIRMED, unconfirmed), + (_('On-chain'), COLOR_CONFIRMED, confirmed), + (_('Lightning'), COLOR_LIGHTNING, lightning), + (_('Lightning frozen'), COLOR_FROZEN_LIGHTNING, f_lightning), + ] + ) vbox = QVBoxLayout() vbox.addWidget(piechart) diff --git a/electrum/gui/qt/channels_list.py b/electrum/gui/qt/channels_list.py index 6340645c3..cafe8e5a9 100644 --- a/electrum/gui/qt/channels_list.py +++ b/electrum/gui/qt/channels_list.py @@ -22,7 +22,7 @@ from electrum.gui import messages from .util import (MyTreeView, WindowModalDialog, Buttons, OkButton, CancelButton, EnterButton, WaitingDialog, MONOSPACE_FONT, ColorScheme) from .amountedit import BTCAmountEdit, FreezableLineEdit -from .util import read_QIcon +from .util import read_QIcon, font_height ROLE_CHANNEL_ID = Qt.UserRole @@ -442,9 +442,10 @@ class ChanFeatNoOnchainBackup(ChannelFeature): class ChannelFeatureIcons: - ICON_SIZE = QSize(16, 16) def __init__(self, features: Sequence['ChannelFeature']): + size = max(16, font_height()) + self.icon_size = QSize(size, size) self.features = features @classmethod @@ -466,17 +467,17 @@ class ChannelFeatureIcons: painter.save() cur_x = rect.x() for feat in self.features: - icon_rect = QRect(cur_x, rect.y(), self.ICON_SIZE.width(), self.ICON_SIZE.height()) + icon_rect = QRect(cur_x, rect.y(), self.icon_size.width(), self.icon_size.height()) feat.rect = icon_rect if rect.contains(icon_rect): # stay inside parent - painter.drawPixmap(icon_rect, feat.icon().pixmap(self.ICON_SIZE)) - cur_x += self.ICON_SIZE.width() + 1 + painter.drawPixmap(icon_rect, feat.icon().pixmap(self.icon_size)) + cur_x += self.icon_size.width() + 1 painter.restore() def sizeHint(self, default_size: QSize) -> QSize: if not self.features: return default_size - width = len(self.features) * (self.ICON_SIZE.width() + 1) + width = len(self.features) * (self.icon_size.width() + 1) return QSize(width, default_size.height()) def show_tooltip(self, evt: QHelpEvent) -> bool: diff --git a/electrum/gui/qt/console.py b/electrum/gui/qt/console.py index 5ae9fc586..2841fddaa 100644 --- a/electrum/gui/qt/console.py +++ b/electrum/gui/qt/console.py @@ -13,7 +13,7 @@ from PyQt5 import QtWidgets from electrum import util from electrum.i18n import _ -from .util import MONOSPACE_FONT +from .util import MONOSPACE_FONT, font_height # sys.ps1 and sys.ps2 are only declared if an interpreter is in interactive mode. sys.ps1 = '>>> ' @@ -32,7 +32,7 @@ class OverlayLabel(QtWidgets.QLabel): ''' def __init__(self, text, parent): super().__init__(text, parent) - self.setMinimumHeight(150) + self.setMinimumHeight(max(150, 10 * font_height())) self.setGeometry(0, 0, self.width(), self.height()) self.setStyleSheet(self.STYLESHEET) self.setMargin(0) diff --git a/electrum/gui/qt/exception_window.py b/electrum/gui/qt/exception_window.py index 3be2dc735..1a920aa15 100644 --- a/electrum/gui/qt/exception_window.py +++ b/electrum/gui/qt/exception_window.py @@ -36,7 +36,7 @@ from electrum.logging import Logger from electrum import constants from electrum.network import Network -from .util import MessageBoxMixin, read_QIcon, WaitingDialog +from .util import MessageBoxMixin, read_QIcon, WaitingDialog, font_height if TYPE_CHECKING: from electrum.simple_config import SimpleConfig @@ -76,7 +76,7 @@ class Exception_Window(BaseCrashReporter, QWidget, MessageBoxMixin, Logger): main_box.addWidget(QLabel(BaseCrashReporter.DESCRIBE_ERROR_MESSAGE)) self.description_textfield = QTextEdit() - self.description_textfield.setFixedHeight(50) + self.description_textfield.setFixedHeight(4 * font_height()) self.description_textfield.setPlaceholderText(self.USER_COMMENT_PLACEHOLDER) main_box.addWidget(self.description_textfield) diff --git a/electrum/gui/qt/installwizard.py b/electrum/gui/qt/installwizard.py index 3d4541ff6..5168f464e 100644 --- a/electrum/gui/qt/installwizard.py +++ b/electrum/gui/qt/installwizard.py @@ -26,7 +26,7 @@ from electrum.i18n import _ from .seed_dialog import SeedLayout, KeysLayout from .network_dialog import NetworkChoiceLayout from .util import (MessageBoxMixin, Buttons, icon_path, ChoicesLayout, WWLabel, - InfoButton, char_width_in_lineedit, PasswordLineEdit) + InfoButton, char_width_in_lineedit, PasswordLineEdit, font_height) from .password_dialog import PasswordLayout, PasswordLayoutForHW, PW_NEW from .bip39_recovery_dialog import Bip39RecoveryDialog from electrum.plugin import run_hook, Plugins @@ -58,10 +58,10 @@ MSG_PASSPHRASE_WARN_ISSUE4566 = _("Warning") + ": "\ class CosignWidget(QWidget): - size = 120 def __init__(self, m, n): QWidget.__init__(self) + self.size = max(120, 9 * font_height()) self.R = QRect(0, 0, self.size, self.size) self.setGeometry(self.R) self.setMinimumHeight(self.size) diff --git a/electrum/gui/qt/lightning_tx_dialog.py b/electrum/gui/qt/lightning_tx_dialog.py index a5c0b479b..e51411796 100644 --- a/electrum/gui/qt/lightning_tx_dialog.py +++ b/electrum/gui/qt/lightning_tx_dialog.py @@ -33,7 +33,7 @@ from PyQt5.QtWidgets import QVBoxLayout, QLabel, QGridLayout from electrum.i18n import _ from electrum.lnworker import PaymentDirection -from .util import WindowModalDialog, ShowQRLineEdit, ColorScheme, Buttons, CloseButton, MONOSPACE_FONT +from .util import WindowModalDialog, ShowQRLineEdit, ColorScheme, Buttons, CloseButton, font_height from .qrtextedit import ShowQRTextEdit if TYPE_CHECKING: @@ -80,7 +80,7 @@ class LightningTxDialog(WindowModalDialog): vbox.addWidget(self.preimage_e) vbox.addWidget(QLabel(_("Lightning Invoice") + ":")) self.invoice_e = ShowQRTextEdit(self.invoice, config=self.config) - self.invoice_e.setMaximumHeight(150) + self.invoice_e.setMaximumHeight(max(150, 10 * font_height())) self.invoice_e.addCopyButton() vbox.addWidget(self.invoice_e) vbox.addLayout(Buttons(CloseButton(self))) diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index bb36b7a31..e938b4494 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -38,7 +38,7 @@ import asyncio from typing import Optional, TYPE_CHECKING, Sequence, List, Union, Dict, Set import concurrent.futures -from PyQt5.QtGui import QPixmap, QKeySequence, QIcon, QCursor, QFont +from PyQt5.QtGui import QPixmap, QKeySequence, QIcon, QCursor, QFont, QFontMetrics from PyQt5.QtCore import Qt, QRect, QStringListModel, QSize, pyqtSignal from PyQt5.QtWidgets import (QMessageBox, QSystemTrayIcon, QTabWidget, QMenuBar, QFileDialog, QCheckBox, QLabel, @@ -88,7 +88,7 @@ from .util import (read_QIcon, ColorScheme, text_dialog, icon_path, WaitingDialo import_meta_gui, export_meta_gui, filename_field, address_field, char_width_in_lineedit, webopen, TRANSACTION_FILE_EXTENSION_FILTER_ANY, MONOSPACE_FONT, - getOpenFileName, getSaveFileName, BlockingWaitingDialog) + getOpenFileName, getSaveFileName, BlockingWaitingDialog, font_height) from .util import ButtonsLineEdit, ShowQRLineEdit from .util import QtEventListener, qt_event_listener, event_listener from .installwizard import WIF_HELP_TEXT @@ -117,10 +117,11 @@ class StatusBarButton(QToolButton): self.setToolTip(tooltip) self.setToolButtonStyle(Qt.ToolButtonTextBesideIcon) self.setAutoRaise(True) - self.setMaximumWidth(25) + size = max(25, round(1.8 * font_height())) + self.setMaximumWidth(size) self.clicked.connect(self.onPress) self.func = func - self.setIconSize(QSize(25,25)) + self.setIconSize(QSize(size, size)) self.setCursor(QCursor(Qt.PointingHandCursor)) def onPress(self, checked=False): @@ -1528,13 +1529,16 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener): def create_status_bar(self): sb = QStatusBar() - sb.setFixedHeight(35) self.balance_label = BalanceToolButton() self.balance_label.setText("Loading wallet...") self.balance_label.setAutoRaise(True) self.balance_label.clicked.connect(self.show_balance_dialog) sb.addWidget(self.balance_label) + font_height = QFontMetrics(self.balance_label.font()).height() + sb_height = max(35, int(2 * font_height)) + sb.setFixedHeight(sb_height) + # remove border of all items in status bar self.setStyleSheet("QStatusBar::item { border: 0px;} ") @@ -1813,7 +1817,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener): ks_w.setLayout(ks_vbox) mpk_text = ShowQRTextEdit(ks.get_master_public_key(), config=self.config) - mpk_text.setMaximumHeight(150) + mpk_text.setMaximumHeight(max(150, 10 * font_height())) mpk_text.addCopyButton() run_hook('show_xpub_button', mpk_text, ks) ks_vbox.addWidget(WWLabel(_("Master Public Key"))) diff --git a/electrum/gui/qt/new_channel_dialog.py b/electrum/gui/qt/new_channel_dialog.py index a81a4659c..daf65b9a5 100644 --- a/electrum/gui/qt/new_channel_dialog.py +++ b/electrum/gui/qt/new_channel_dialog.py @@ -1,6 +1,6 @@ from typing import TYPE_CHECKING, Optional -from PyQt5.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton, QComboBox, QLineEdit +from PyQt5.QtWidgets import QLabel, QVBoxLayout, QGridLayout, QPushButton, QComboBox, QLineEdit, QSpacerItem, QWidget, QHBoxLayout from electrum.i18n import _ from electrum.transaction import PartialTxOutput, PartialTransaction @@ -11,7 +11,8 @@ from electrum.util import NotEnoughFunds, NoDynamicFeeEstimates from .util import (WindowModalDialog, Buttons, OkButton, CancelButton, - EnterButton, ColorScheme, WWLabel, read_QIcon, IconLabel) + EnterButton, ColorScheme, WWLabel, read_QIcon, IconLabel, + char_width_in_lineedit) from .amountedit import BTCAmountEdit @@ -49,14 +50,17 @@ class NewChannelDialog(WindowModalDialog): self.trampoline_combo.setCurrentIndex(1) self.amount_e = BTCAmountEdit(self.window.get_decimal_point) self.amount_e.setAmount(amount_sat) + + btn_width = 10 * char_width_in_lineedit() self.min_button = EnterButton(_("Min"), self.spend_min) self.min_button.setEnabled(bool(self.min_amount_sat)) + self.min_button.setFixedWidth(btn_width) self.max_button = EnterButton(_("Max"), self.spend_max) - self.max_button.setFixedWidth(100) + self.max_button.setFixedWidth(btn_width) self.max_button.setCheckable(True) self.clear_button = QPushButton(self, text=_('Clear')) self.clear_button.clicked.connect(self.on_clear) - self.clear_button.setFixedWidth(100) + self.clear_button.setFixedWidth(btn_width) h = QGridLayout() if self.network.channel_db: h.addWidget(QLabel(_('Remote Node ID')), 0, 0) @@ -66,10 +70,16 @@ class NewChannelDialog(WindowModalDialog): h.addWidget(QLabel(_('Remote Node')), 0, 0) h.addWidget(self.trampoline_combo, 0, 1, 1, 4) h.addWidget(QLabel('Amount'), 2, 0) - h.addWidget(self.amount_e, 2, 1) - h.addWidget(self.min_button, 2, 2) - h.addWidget(self.max_button, 2, 3) - h.addWidget(self.clear_button, 2, 4) + + amt_hbox = QHBoxLayout() + amt_hbox.setContentsMargins(0, 0, 0, 0) + amt_hbox.addWidget(self.amount_e) + amt_hbox.addWidget(self.min_button) + amt_hbox.addWidget(self.max_button) + amt_hbox.addWidget(self.clear_button) + amt_hbox.addStretch() + h.addLayout(amt_hbox, 2, 1, 1, 4) + vbox.addLayout(h) vbox.addStretch() ok_button = OkButton(self) diff --git a/electrum/gui/qt/seed_dialog.py b/electrum/gui/qt/seed_dialog.py index 4d08debbc..1a2eb84a6 100644 --- a/electrum/gui/qt/seed_dialog.py +++ b/electrum/gui/qt/seed_dialog.py @@ -38,7 +38,7 @@ from electrum import slip39 from .util import (Buttons, OkButton, WWLabel, ButtonsTextEdit, icon_path, EnterButton, CloseButton, WindowModalDialog, ColorScheme, - ChoicesLayout) + ChoicesLayout, font_height) from .qrtextedit import ShowQRTextEdit, ScanQRTextEdit from .completion_text_edit import CompletionTextEdit @@ -157,7 +157,7 @@ class SeedLayout(QVBoxLayout): self.seed_e.textChanged.connect(self.on_edit) self.initialize_completer() - self.seed_e.setMaximumHeight(75) + self.seed_e.setMaximumHeight(max(75, 5 * font_height())) hbox = QHBoxLayout() if icon: logo = QLabel() diff --git a/electrum/gui/qt/send_tab.py b/electrum/gui/qt/send_tab.py index 00671159e..ceeaa4a9b 100644 --- a/electrum/gui/qt/send_tab.py +++ b/electrum/gui/qt/send_tab.py @@ -26,7 +26,7 @@ from electrum.lnaddr import lndecode, LnInvoiceException from electrum.lnurl import decode_lnurl, request_lnurl, callback_lnurl, LNURLError, LNURL6Data from .amountedit import AmountEdit, BTCAmountEdit, SizedFreezableLineEdit -from .util import WaitingDialog, HelpLabel, MessageBoxMixin, EnterButton +from .util import WaitingDialog, HelpLabel, MessageBoxMixin, EnterButton, char_width_in_lineedit from .confirm_tx_dialog import ConfirmTxDialog from .transaction_dialog import PreviewTxDialog @@ -119,7 +119,8 @@ class SendTab(QWidget, MessageBoxMixin, Logger): self.window.connect_fields(self.amount_e, self.fiat_send_e) self.max_button = EnterButton(_("Max"), self.spend_max) - self.max_button.setFixedWidth(100) + btn_width = 10 * char_width_in_lineedit() + self.max_button.setFixedWidth(btn_width) self.max_button.setCheckable(True) grid.addWidget(self.max_button, 3, 3) diff --git a/electrum/gui/qt/swap_dialog.py b/electrum/gui/qt/swap_dialog.py index 68e2240ec..6cfd1060f 100644 --- a/electrum/gui/qt/swap_dialog.py +++ b/electrum/gui/qt/swap_dialog.py @@ -9,7 +9,7 @@ from electrum.lnutil import ln_dummy_address from electrum.transaction import PartialTxOutput, PartialTransaction from .util import (WindowModalDialog, Buttons, OkButton, CancelButton, - EnterButton, ColorScheme, WWLabel, read_QIcon, IconLabel) + EnterButton, ColorScheme, WWLabel, read_QIcon, IconLabel, char_width_in_lineedit) from .amountedit import BTCAmountEdit from .fee_slider import FeeSlider, FeeComboBox @@ -43,7 +43,8 @@ class SwapDialog(WindowModalDialog): self.send_amount_e = BTCAmountEdit(self.window.get_decimal_point) self.recv_amount_e = BTCAmountEdit(self.window.get_decimal_point) self.max_button = EnterButton(_("Max"), self.spend_max) - self.max_button.setFixedWidth(100) + btn_width = 10 * char_width_in_lineedit() + self.max_button.setFixedWidth(btn_width) self.max_button.setCheckable(True) self.toggle_button = QPushButton(u'\U000021c4') self.toggle_button.setEnabled(is_reverse is None) diff --git a/electrum/gui/qt/util.py b/electrum/gui/qt/util.py index 2819d2aac..41d8ec6e1 100644 --- a/electrum/gui/qt/util.py +++ b/electrum/gui/qt/util.py @@ -1403,10 +1403,11 @@ def read_QIcon(icon_basename): return QIcon(icon_path(icon_basename)) class IconLabel(QWidget): - IconSize = QSize(16, 16) HorizontalSpacing = 2 def __init__(self, *, text='', final_stretch=True): super(QWidget, self).__init__() + size = max(16, font_height()) + self.icon_size = QSize(size, size) layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) @@ -1421,7 +1422,7 @@ class IconLabel(QWidget): def setText(self, text): self.label.setText(text) def setIcon(self, icon): - self.icon.setPixmap(icon.pixmap(self.IconSize)) + self.icon.setPixmap(icon.pixmap(self.icon_size)) self.icon.repaint() # macOS hack for #6269 def get_default_language(): @@ -1435,6 +1436,10 @@ def char_width_in_lineedit() -> int: return max(9, char_width) +def font_height() -> int: + return QFontMetrics(QLabel().font()).height() + + def webopen(url: str): if sys.platform == 'linux' and os.environ.get('APPIMAGE'): # When on Linux webbrowser.open can fail in AppImage because it can't find the correct libdbus. diff --git a/electrum/gui/qt/watchtower_dialog.py b/electrum/gui/qt/watchtower_dialog.py index ac1a0693d..89033ae9b 100644 --- a/electrum/gui/qt/watchtower_dialog.py +++ b/electrum/gui/qt/watchtower_dialog.py @@ -67,7 +67,7 @@ class WatchtowerDialog(QDialog): assert self.network self.lnwatcher = self.network.local_watchtower self.setWindowTitle(_('Watchtower')) - self.setMinimumSize(600, 20) + self.setMinimumSize(600, 200) self.size_label = QLabel() self.watcher_list = WatcherList(self) diff --git a/electrum/plugins/virtualkeyboard/qt.py b/electrum/plugins/virtualkeyboard/qt.py index 3016a77ce..a234462af 100644 --- a/electrum/plugins/virtualkeyboard/qt.py +++ b/electrum/plugins/virtualkeyboard/qt.py @@ -1,6 +1,7 @@ import random from PyQt5.QtWidgets import (QVBoxLayout, QGridLayout, QPushButton) +from PyQt5.QtGui import QFontMetrics from electrum.plugin import BasePlugin, hook from electrum.i18n import _ @@ -12,8 +13,9 @@ class Plugin(BasePlugin): @hook def password_dialog(self, pw, grid, pos): - vkb_button = QPushButton(_("+")) - vkb_button.setFixedWidth(20) + vkb_button = QPushButton("+") + font_height = QFontMetrics(vkb_button.font()).height() + vkb_button.setFixedWidth(round(1.7 * font_height)) vkb_button.clicked.connect(lambda: self.toggle_vkb(grid, pw)) grid.addWidget(vkb_button, pos, 2) self.kb_pos = 2 @@ -47,13 +49,16 @@ class Plugin(BasePlugin): def add_target(t): return lambda: pw.setText(str(pw.text()) + t) + font_height = QFontMetrics(QPushButton().font()).height() + btn_size = max(25, round(1.7 * font_height)) + vbox = QVBoxLayout() grid = QGridLayout() grid.setSpacing(2) for i in range(n): l_button = QPushButton(chars[s[i]]) - l_button.setFixedWidth(25) - l_button.setFixedHeight(25) + l_button.setFixedWidth(btn_size) + l_button.setFixedHeight(btn_size) l_button.clicked.connect(add_target(chars[s[i]])) grid.addWidget(l_button, i // 6, i % 6)