diff --git a/electrum/gui/qt/amountedit.py b/electrum/gui/qt/amountedit.py index c3920b9d6..8fc63fa1a 100644 --- a/electrum/gui/qt/amountedit.py +++ b/electrum/gui/qt/amountedit.py @@ -3,9 +3,11 @@ from decimal import Decimal from PyQt5.QtCore import pyqtSignal, Qt -from PyQt5.QtGui import QPalette, QPainter +from PyQt5.QtGui import QPalette, QPainter, QFontMetrics from PyQt5.QtWidgets import (QLineEdit, QStyle, QStyleOptionFrame) +from .util import char_width_in_lineedit + from electrum.util import (format_satoshis_plain, decimal_point_to_base_unit_name, FEERATE_PRECISION, quantize_feerate) @@ -24,7 +26,7 @@ class AmountEdit(MyLineEdit): def __init__(self, base_unit, is_int=False, parent=None): QLineEdit.__init__(self, parent) # This seems sufficient for hundred-BTC amounts with 8 decimals - self.setFixedWidth(140) + self.setFixedWidth(16 * char_width_in_lineedit()) self.base_unit = base_unit self.textChanged.connect(self.numbify) self.is_int = is_int diff --git a/electrum/gui/qt/installwizard.py b/electrum/gui/qt/installwizard.py index 309bf03ee..722940042 100644 --- a/electrum/gui/qt/installwizard.py +++ b/electrum/gui/qt/installwizard.py @@ -23,7 +23,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) + InfoButton, char_width_in_lineedit) from .password_dialog import PasswordLayout, PasswordLayoutForHW, PW_NEW from electrum.plugin import run_hook @@ -180,7 +180,7 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard): vbox.addWidget(self.msg_label) hbox2 = QHBoxLayout() self.pw_e = QLineEdit('', self) - self.pw_e.setFixedWidth(150) + self.pw_e.setFixedWidth(17 * char_width_in_lineedit()) self.pw_e.setEchoMode(2) self.pw_label = QLabel(_('Password') + ':') hbox2.addWidget(self.pw_label) diff --git a/electrum/gui/qt/main_window.py b/electrum/gui/qt/main_window.py index 474ff563e..72add77a1 100644 --- a/electrum/gui/qt/main_window.py +++ b/electrum/gui/qt/main_window.py @@ -85,7 +85,7 @@ from .util import (read_QIcon, ColorScheme, text_dialog, icon_path, WaitingDialo OkButton, InfoButton, WWLabel, TaskThread, CancelButton, CloseButton, HelpButton, MessageBoxMixin, EnterButton, expiration_values, ButtonsLineEdit, CopyCloseButton, import_meta_gui, export_meta_gui, - filename_field, address_field) + filename_field, address_field, char_width_in_lineedit) from .installwizard import WIF_HELP_TEXT from .history_list import HistoryList, HistoryModel from .update_checker import UpdateCheck, UpdateCheckThread @@ -1216,7 +1216,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger): lambda: self.fiat_send_e.setFrozen(self.amount_e.isReadOnly())) self.max_button = EnterButton(_("Max"), self.spend_max) - self.max_button.setFixedWidth(140) + self.max_button.setFixedWidth(self.amount_e.width()) self.max_button.setCheckable(True) grid.addWidget(self.max_button, 4, 3) hbox = QHBoxLayout() @@ -1248,7 +1248,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger): self.spend_max() if self.max_button.isChecked() else self.update_fee() self.fee_slider = FeeSlider(self, self.config, fee_cb) - self.fee_slider.setFixedWidth(140) + self.fee_slider.setFixedWidth(self.amount_e.width()) def on_fee_or_feerate(edit_changed, editing_finished): edit_other = self.feerate_e if edit_changed == self.fee_e else self.fee_e @@ -1271,7 +1271,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger): self.size_e = TxSizeLabel() self.size_e.setAlignment(Qt.AlignCenter) self.size_e.setAmount(0) - self.size_e.setFixedWidth(140) + self.size_e.setFixedWidth(self.amount_e.width()) self.size_e.setStyleSheet(ColorScheme.DEFAULT.as_stylesheet()) self.feerate_e = FeerateEdit(lambda: 0) @@ -1293,7 +1293,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger): self.show_message(title=_('Fee rounding'), msg=text) self.feerounding_icon = QPushButton(read_QIcon('info.png'), '') - self.feerounding_icon.setFixedWidth(20) + self.feerounding_icon.setFixedWidth(round(2.2 * char_width_in_lineedit())) self.feerounding_icon.setFlat(True) self.feerounding_icon.clicked.connect(feerounding_onclick) self.feerounding_icon.setVisible(False) @@ -2198,9 +2198,9 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger): vbox.addWidget(QLabel(_('New Contact') + ':')) grid = QGridLayout() line1 = QLineEdit() - line1.setFixedWidth(280) + line1.setFixedWidth(32 * char_width_in_lineedit()) line2 = QLineEdit() - line2.setFixedWidth(280) + line2.setFixedWidth(32 * char_width_in_lineedit()) grid.addWidget(QLabel(_("Address")), 1, 0) grid.addWidget(line1, 1, 1) grid.addWidget(QLabel(_("Name")), 2, 0) diff --git a/electrum/gui/qt/network_dialog.py b/electrum/gui/qt/network_dialog.py index 31c21f73f..511700c35 100644 --- a/electrum/gui/qt/network_dialog.py +++ b/electrum/gui/qt/network_dialog.py @@ -32,6 +32,7 @@ from PyQt5.QtCore import Qt, pyqtSignal, QThread from PyQt5.QtWidgets import (QTreeWidget, QTreeWidgetItem, QMenu, QGridLayout, QComboBox, QLineEdit, QDialog, QVBoxLayout, QHeaderView, QCheckBox, QTabWidget, QWidget, QLabel) +from PyQt5.QtGui import QFontMetrics from electrum.i18n import _ from electrum import constants, blockchain @@ -39,7 +40,7 @@ from electrum.interface import serialize_server, deserialize_server from electrum.network import Network from electrum.logging import get_logger -from .util import Buttons, CloseButton, HelpButton, read_QIcon +from .util import Buttons, CloseButton, HelpButton, read_QIcon, char_width_in_lineedit _logger = get_logger(__name__) @@ -214,14 +215,17 @@ class NetworkChoiceLayout(object): tabs.addTab(server_tab, _('Server')) tabs.addTab(proxy_tab, _('Proxy')) + fixed_width_hostname = 24 * char_width_in_lineedit() + fixed_width_port = 6 * char_width_in_lineedit() + # server tab grid = QGridLayout(server_tab) grid.setSpacing(8) self.server_host = QLineEdit() - self.server_host.setFixedWidth(200) + self.server_host.setFixedWidth(fixed_width_hostname) self.server_port = QLineEdit() - self.server_port.setFixedWidth(60) + self.server_port.setFixedWidth(fixed_width_port) self.autoconnect_cb = QCheckBox(_('Select server automatically')) self.autoconnect_cb.setEnabled(self.config.is_modifiable('auto_connect')) @@ -258,15 +262,15 @@ class NetworkChoiceLayout(object): self.proxy_mode = QComboBox() self.proxy_mode.addItems(['SOCKS4', 'SOCKS5']) self.proxy_host = QLineEdit() - self.proxy_host.setFixedWidth(200) + self.proxy_host.setFixedWidth(fixed_width_hostname) self.proxy_port = QLineEdit() - self.proxy_port.setFixedWidth(60) + self.proxy_port.setFixedWidth(fixed_width_port) self.proxy_user = QLineEdit() self.proxy_user.setPlaceholderText(_("Proxy user")) self.proxy_password = QLineEdit() self.proxy_password.setPlaceholderText(_("Password")) self.proxy_password.setEchoMode(QLineEdit.Password) - self.proxy_password.setFixedWidth(60) + self.proxy_password.setFixedWidth(fixed_width_port) self.proxy_mode.currentIndexChanged.connect(self.set_proxy) self.proxy_host.editingFinished.connect(self.set_proxy) diff --git a/electrum/gui/qt/util.py b/electrum/gui/qt/util.py index 066e7bd15..ba5411b5c 100644 --- a/electrum/gui/qt/util.py +++ b/electrum/gui/qt/util.py @@ -10,7 +10,7 @@ from functools import partial, lru_cache from typing import NamedTuple, Callable, Optional, TYPE_CHECKING, Union, List, Dict from PyQt5.QtGui import (QFont, QColor, QCursor, QPixmap, QStandardItem, - QPalette, QIcon) + QPalette, QIcon, QFontMetrics) from PyQt5.QtCore import (Qt, QPersistentModelIndex, QModelIndex, pyqtSignal, QCoreApplication, QItemSelectionModel, QThread, QSortFilterProxyModel, QSize, QLocale) @@ -127,7 +127,7 @@ class HelpButton(QPushButton): QPushButton.__init__(self, '?') self.help_text = text self.setFocusPolicy(Qt.NoFocus) - self.setFixedWidth(20) + self.setFixedWidth(round(2.2 * char_width_in_lineedit())) self.clicked.connect(self.onclick) def onclick(self): @@ -143,7 +143,7 @@ class InfoButton(QPushButton): QPushButton.__init__(self, 'Info') self.help_text = text self.setFocusPolicy(Qt.NoFocus) - self.setFixedWidth(60) + self.setFixedWidth(6 * char_width_in_lineedit()) self.clicked.connect(self.onclick) def onclick(self): @@ -872,6 +872,12 @@ class FromList(QTreeWidget): self.header().setSectionResizeMode(1, sm) +def char_width_in_lineedit() -> int: + char_width = QFontMetrics(QLineEdit().font()).averageCharWidth() + # 'averageCharWidth' seems to underestimate on Windows, hence 'max()' + return max(9, char_width) + + if __name__ == "__main__": app = QApplication([]) t = WaitingDialog(None, 'testing ...', lambda: [time.sleep(1)], lambda x: QMessageBox.information(None, 'done', "done")) diff --git a/electrum/plugins/hw_wallet/qt.py b/electrum/plugins/hw_wallet/qt.py index a93a9d30c..5a8c9dfe7 100644 --- a/electrum/plugins/hw_wallet/qt.py +++ b/electrum/plugins/hw_wallet/qt.py @@ -32,7 +32,7 @@ from PyQt5.QtWidgets import QVBoxLayout, QLineEdit, QHBoxLayout, QLabel from electrum.gui.qt.password_dialog import PasswordLayout, PW_PASSPHRASE from electrum.gui.qt.util import (read_QIcon, WWLabel, OkButton, WindowModalDialog, - Buttons, CancelButton, TaskThread) + Buttons, CancelButton, TaskThread, char_width_in_lineedit) from electrum.i18n import _ from electrum.logging import Logger @@ -149,7 +149,7 @@ class QtHandlerBase(QObject, Logger): hbox = QHBoxLayout(dialog) hbox.addWidget(QLabel(msg)) text = QLineEdit() - text.setMaximumWidth(100) + text.setMaximumWidth(12 * char_width_in_lineedit()) text.returnPressed.connect(dialog.accept) hbox.addWidget(text) hbox.addStretch(1)