diff --git a/electrum/gui/qt/util.py b/electrum/gui/qt/util.py index 4817855be..4a06f6a29 100644 --- a/electrum/gui/qt/util.py +++ b/electrum/gui/qt/util.py @@ -1242,14 +1242,21 @@ def getSaveFileName( def icon_path(icon_basename: str): return resource_path('gui', 'icons', icon_basename) +def internal_plugin_icon_path(plugin_name, icon_basename: str): + return resource_path('plugins', plugin_name, icon_basename) + @lru_cache(maxsize=1000) def read_QIcon(icon_basename: str) -> QIcon: return QIcon(icon_path(icon_basename)) -def read_QIcon_from_bytes(b: bytes) -> QIcon: +def read_QPixmap_from_bytes(b: bytes) -> QPixmap: qp = QPixmap() qp.loadFromData(b) + return qp + +def read_QIcon_from_bytes(b: bytes) -> QIcon: + qp = read_QPixmap_from_bytes(b) return QIcon(qp) class IconLabel(QWidget): diff --git a/electrum/plugin.py b/electrum/plugin.py index 33294be34..eb7a8f49d 100644 --- a/electrum/plugin.py +++ b/electrum/plugin.py @@ -441,13 +441,16 @@ class BasePlugin(Logger): raise NotImplementedError() def read_file(self, filename: str) -> bytes: - """ note: only for external plugins """ import zipfile - plugin_filename = self.parent.external_plugin_path(self.name) - with zipfile.ZipFile(plugin_filename) as myzip: - with myzip.open(os.path.join(self.name, filename)) as myfile: - s = myfile.read() - return s + if self.name in self.parent.external_plugin_metadata: + plugin_filename = self.parent.external_plugin_path(self.name) + with zipfile.ZipFile(plugin_filename) as myzip: + with myzip.open(os.path.join(self.name, filename)) as myfile: + return myfile.read() + else: + path = os.path.join(os.path.dirname(__file__), 'plugins', self.name, filename) + with open(path, 'rb') as myfile: + return myfile.read() class DeviceUnpairableError(UserFacingException): pass diff --git a/electrum/gui/icons/bitbox02.png b/electrum/plugins/bitbox02/bitbox02.png similarity index 100% rename from electrum/gui/icons/bitbox02.png rename to electrum/plugins/bitbox02/bitbox02.png diff --git a/electrum/gui/icons/bitbox02_unpaired.png b/electrum/plugins/bitbox02/bitbox02_unpaired.png similarity index 100% rename from electrum/gui/icons/bitbox02_unpaired.png rename to electrum/plugins/bitbox02/bitbox02_unpaired.png diff --git a/electrum/gui/icons/coldcard.png b/electrum/plugins/coldcard/coldcard.png similarity index 100% rename from electrum/gui/icons/coldcard.png rename to electrum/plugins/coldcard/coldcard.png diff --git a/electrum/gui/icons/coldcard.svg b/electrum/plugins/coldcard/coldcard.svg similarity index 100% rename from electrum/gui/icons/coldcard.svg rename to electrum/plugins/coldcard/coldcard.svg diff --git a/electrum/gui/icons/coldcard_unpaired.png b/electrum/plugins/coldcard/coldcard_unpaired.png similarity index 100% rename from electrum/gui/icons/coldcard_unpaired.png rename to electrum/plugins/coldcard/coldcard_unpaired.png diff --git a/electrum/gui/icons/coldcard_unpaired.svg b/electrum/plugins/coldcard/coldcard_unpaired.svg similarity index 100% rename from electrum/gui/icons/coldcard_unpaired.svg rename to electrum/plugins/coldcard/coldcard_unpaired.svg diff --git a/electrum/gui/icons/digitalbitbox.png b/electrum/plugins/digitalbitbox/digitalbitbox.png similarity index 100% rename from electrum/gui/icons/digitalbitbox.png rename to electrum/plugins/digitalbitbox/digitalbitbox.png diff --git a/electrum/gui/icons/digitalbitbox_unpaired.png b/electrum/plugins/digitalbitbox/digitalbitbox_unpaired.png similarity index 100% rename from electrum/gui/icons/digitalbitbox_unpaired.png rename to electrum/plugins/digitalbitbox/digitalbitbox_unpaired.png diff --git a/electrum/plugins/hw_wallet/qt.py b/electrum/plugins/hw_wallet/qt.py index c75d1be04..99a58ec9b 100644 --- a/electrum/plugins/hw_wallet/qt.py +++ b/electrum/plugins/hw_wallet/qt.py @@ -36,6 +36,7 @@ from electrum.gui.qt.util import (read_QIcon, WWLabel, OkButton, WindowModalDial Buttons, CancelButton, TaskThread, char_width_in_lineedit, PasswordLineEdit) from electrum.gui.qt.main_window import StatusBarButton +from electrum.gui.qt.util import read_QIcon_from_bytes from electrum.i18n import _ from electrum.logging import Logger @@ -92,8 +93,9 @@ class QtHandlerBase(HardwareHandlerBase, QObject, Logger): def _update_status(self, paired): if hasattr(self, 'button'): button = self.button - icon_name = button.icon_paired if paired else button.icon_unpaired - button.setIcon(read_QIcon(icon_name)) + icon_bytes = button.icon_paired if paired else button.icon_unpaired + icon = read_QIcon_from_bytes(icon_bytes) + button.setIcon(icon) def query_choice(self, msg: str, labels: Sequence[Tuple]): self.done.clear() @@ -222,9 +224,10 @@ class QtPluginBase(object): tooltip = self.device + '\n' + (keystore.label or 'unnamed') cb = partial(self._on_status_bar_button_click, window=window, keystore=keystore) sb = window.statusBar() - button = StatusBarButton(read_QIcon(self.icon_unpaired), tooltip, cb, sb.height()) - button.icon_paired = self.icon_paired - button.icon_unpaired = self.icon_unpaired + icon = read_QIcon_from_bytes(self.read_file(self.icon_unpaired)) + button = StatusBarButton(icon, tooltip, cb, sb.height()) + button.icon_paired = self.read_file(self.icon_paired) + button.icon_unpaired = self.read_file(self.icon_unpaired) sb.addPermanentWidget(button) handler = self.create_handler(window) handler.button = button diff --git a/electrum/gui/icons/jade.png b/electrum/plugins/jade/jade.png similarity index 100% rename from electrum/gui/icons/jade.png rename to electrum/plugins/jade/jade.png diff --git a/electrum/gui/icons/jade_unpaired.png b/electrum/plugins/jade/jade_unpaired.png similarity index 100% rename from electrum/gui/icons/jade_unpaired.png rename to electrum/plugins/jade/jade_unpaired.png diff --git a/electrum/gui/icons/keepkey.png b/electrum/plugins/keepkey/keepkey.png similarity index 100% rename from electrum/gui/icons/keepkey.png rename to electrum/plugins/keepkey/keepkey.png diff --git a/electrum/gui/icons/keepkey_unpaired.png b/electrum/plugins/keepkey/keepkey_unpaired.png similarity index 100% rename from electrum/gui/icons/keepkey_unpaired.png rename to electrum/plugins/keepkey/keepkey_unpaired.png diff --git a/electrum/gui/icons/ledger.png b/electrum/plugins/ledger/ledger.png similarity index 100% rename from electrum/gui/icons/ledger.png rename to electrum/plugins/ledger/ledger.png diff --git a/electrum/gui/icons/ledger_unpaired.png b/electrum/plugins/ledger/ledger_unpaired.png similarity index 100% rename from electrum/gui/icons/ledger_unpaired.png rename to electrum/plugins/ledger/ledger_unpaired.png diff --git a/electrum/plugins/revealer/qt.py b/electrum/plugins/revealer/qt.py index 3e82b07b2..077d5a512 100644 --- a/electrum/plugins/revealer/qt.py +++ b/electrum/plugins/revealer/qt.py @@ -32,10 +32,11 @@ from PyQt6.QtWidgets import (QGridLayout, QVBoxLayout, QHBoxLayout, QLabel, from electrum.plugin import hook from electrum.i18n import _ from electrum.util import make_dir, InvalidPassword, UserCancelled -from electrum.gui.qt.util import (read_QIcon, EnterButton, WWLabel, icon_path, +from electrum.gui.qt.util import (read_QIcon, EnterButton, WWLabel, icon_path, internal_plugin_icon_path, WindowModalDialog, Buttons, CloseButton, OkButton) from electrum.gui.qt.qrtextedit import ScanQRTextEdit from electrum.gui.qt.main_window import StatusBarButton +from electrum.gui.qt.util import read_QIcon_from_bytes, read_QPixmap_from_bytes from .revealer import RevealerPlugin @@ -69,6 +70,7 @@ class Plugin(RevealerPlugin): self.extension = False self._init_qt_received = False + self.icon_bytes = self.read_file("revealer.png") @hook def init_qt(self, gui: 'ElectrumGui'): @@ -81,8 +83,10 @@ class Plugin(RevealerPlugin): @hook def create_status_bar(self, sb): - b = StatusBarButton(read_QIcon('revealer.png'), "Revealer "+_("Visual Cryptography Plugin"), - partial(self.setup_dialog, sb), sb.height()) + b = StatusBarButton( + read_QIcon_from_bytes(self.icon_bytes), + "Revealer "+_("Visual Cryptography Plugin"), + partial(self.setup_dialog, sb), sb.height()) sb.addPermanentWidget(b) def requires_settings(self): @@ -125,7 +129,7 @@ class Plugin(RevealerPlugin): logo_label = QLabel() # Set the logo label pixmap. - logo_label.setPixmap(QPixmap(icon_path('revealer.png'))) + logo_label.setPixmap(read_QPixmap_from_bytes(self.icon_bytes)) # Align the logo label to the top left. logo_label.setAlignment(Qt.AlignmentFlag.AlignLeft) @@ -308,7 +312,7 @@ class Plugin(RevealerPlugin): logo_label = QLabel() # Set the logo label pixmap. - logo_label.setPixmap(QPixmap(icon_path('revealer.png'))) + logo_label.setPixmap(read_QPixmap_from_bytes(self.icon_bytes)) # Align the logo label to the top left. logo_label.setAlignment(Qt.AlignmentFlag.AlignLeft) @@ -670,7 +674,7 @@ class Plugin(RevealerPlugin): painter.drawLine(base_img.width()-(dist_h), 0, base_img.width()-(dist_h), base_img.height()) painter.drawImage(((total_distance_h))+11, ((total_distance_h))+11, - QImage(icon_path('electrumb.png')).scaledToWidth(round(2.1*total_distance_h), Qt.TransformationMode.SmoothTransformation)) + QImage(internal_icon_path('electrumb.png')).scaledToWidth(round(2.1*total_distance_h), Qt.TransformationMode.SmoothTransformation)) painter.setPen(QPen(Qt.GlobalColor.white, border_thick*8)) painter.drawLine(int(base_img.width()-total_distance_h-(border_thick*8)/2-(border_thick/2)-2), @@ -696,7 +700,7 @@ class Plugin(RevealerPlugin): painter.drawLine(dist_h, 0, dist_h, base_img.height()) painter.drawLine(0, base_img.height()-dist_v, base_img.width(), base_img.height()-(dist_v)) painter.drawLine(base_img.width()-(dist_h), 0, base_img.width()-(dist_h), base_img.height()) - logo = QImage(icon_path('revealer_c.png')).scaledToWidth(round(1.3*(total_distance_h))) + logo = QImage(internal_plugin_icon_path(self.name, 'revealer_c.png')).scaledToWidth(round(1.3*(total_distance_h))) painter.drawImage(int(total_distance_h+border_thick), int(total_distance_h+border_thick), logo, Qt.TransformationMode.SmoothTransformation) #frame around logo diff --git a/electrum/gui/icons/revealer.png b/electrum/plugins/revealer/revealer.png similarity index 100% rename from electrum/gui/icons/revealer.png rename to electrum/plugins/revealer/revealer.png diff --git a/electrum/gui/icons/safe-t.png b/electrum/plugins/safe_t/safe-t.png similarity index 100% rename from electrum/gui/icons/safe-t.png rename to electrum/plugins/safe_t/safe-t.png diff --git a/electrum/gui/icons/safe-t_unpaired.png b/electrum/plugins/safe_t/safe-t_unpaired.png similarity index 100% rename from electrum/gui/icons/safe-t_unpaired.png rename to electrum/plugins/safe_t/safe-t_unpaired.png diff --git a/electrum/gui/icons/trezor.png b/electrum/plugins/trezor/trezor.png similarity index 100% rename from electrum/gui/icons/trezor.png rename to electrum/plugins/trezor/trezor.png diff --git a/electrum/gui/icons/trezor_unpaired.png b/electrum/plugins/trezor/trezor_unpaired.png similarity index 100% rename from electrum/gui/icons/trezor_unpaired.png rename to electrum/plugins/trezor/trezor_unpaired.png diff --git a/electrum/plugins/trustedcoin/qt.py b/electrum/plugins/trustedcoin/qt.py index 0f98f6c8f..703161904 100644 --- a/electrum/plugins/trustedcoin/qt.py +++ b/electrum/plugins/trustedcoin/qt.py @@ -40,13 +40,14 @@ from electrum.logging import Logger, get_logger from electrum import keystore from electrum.gui.qt.util import (read_QIcon, WindowModalDialog, WaitingDialog, OkButton, - CancelButton, Buttons, icon_path, WWLabel, CloseButton, ColorScheme, + CancelButton, Buttons, icon_path, internal_plugin_icon_path, WWLabel, CloseButton, ColorScheme, ChoiceWidget, PasswordLineEdit, char_width_in_lineedit) from electrum.gui.qt.qrcodewidget import QRCodeWidget from electrum.gui.qt.amountedit import AmountEdit from electrum.gui.qt.main_window import StatusBarButton from electrum.gui.qt.wizard.wallet import WCCreateSeed, WCConfirmSeed, WCHaveSeed, WCEnterExt, WCConfirmExt from electrum.gui.qt.wizard.wizard import WizardComponent +from electrum.gui.qt.util import read_QIcon_from_bytes from .common_qt import TrustedcoinPluginQObject from .trustedcoin import TrustedCoinPlugin, server, DISCLAIMER @@ -103,10 +104,10 @@ class Plugin(TrustedCoinPlugin): _('Therefore, two-factor authentication is disabled.') ]) action = lambda: window.show_message(msg) - icon = read_QIcon("trustedcoin-status-disabled.png") + icon = read_QIcon_from_bytes(self.read_file("trustedcoin-status-disabled.png")) else: action = partial(self.settings_dialog, window) - icon = read_QIcon("trustedcoin-status.png") + icon = read_QIcon_from_bytes(self.read_file("trustedcoin-status.png")) sb = window.statusBar() button = StatusBarButton(icon, _("TrustedCoin"), action, sb.height()) sb.addPermanentWidget(button) @@ -166,6 +167,9 @@ class Plugin(TrustedCoinPlugin): self.waiting_dialog_for_billing_info(window, on_finished=partial(self.show_settings_dialog, window)) + def icon_path(self, name): + return internal_plugin_icon_path(self.name, name) + def show_settings_dialog(self, window, success): if not success: window.show_message(_('Server not reachable.')) @@ -178,7 +182,7 @@ class Plugin(TrustedCoinPlugin): hbox = QHBoxLayout() logo = QLabel() - logo.setPixmap(QPixmap(icon_path("trustedcoin-status.png"))) + logo.setPixmap(QPixmap(self.icon_path("trustedcoin-status.png"))) msg = _('This wallet is protected by TrustedCoin\'s two-factor authentication.') + '
'\ + _("For more information, visit") + " https://api.trustedcoin.com/#/electrum-help" label = QLabel(msg) @@ -228,46 +232,46 @@ class Plugin(TrustedCoinPlugin): wizard.trustedcoin_qhelper = TrustedcoinPluginQObject(self, wizard, None) self.extend_wizard(wizard) if wizard.start_viewstate and wizard.start_viewstate.view.startswith('trustedcoin_'): - wizard.start_viewstate.params.update({'icon': icon_path('trustedcoin-wizard.png')}) + wizard.start_viewstate.params.update({'icon': self.icon_path('trustedcoin-wizard.png')}) def extend_wizard(self, wizard: 'QENewWalletWizard'): super().extend_wizard(wizard) views = { 'trustedcoin_start': { 'gui': WCDisclaimer, - 'params': {'icon': icon_path('trustedcoin-wizard.png')}, + 'params': {'icon': self.icon_path('trustedcoin-wizard.png')}, }, 'trustedcoin_choose_seed': { 'gui': WCChooseSeed, - 'params': {'icon': icon_path('trustedcoin-wizard.png')}, + 'params': {'icon': self.icon_path('trustedcoin-wizard.png')}, }, 'trustedcoin_create_seed': { 'gui': WCCreateSeed, - 'params': {'icon': icon_path('trustedcoin-wizard.png')}, + 'params': {'icon': self.icon_path('trustedcoin-wizard.png')}, }, 'trustedcoin_confirm_seed': { 'gui': WCConfirmSeed, - 'params': {'icon': icon_path('trustedcoin-wizard.png')}, + 'params': {'icon': self.icon_path('trustedcoin-wizard.png')}, }, 'trustedcoin_have_seed': { 'gui': WCHaveSeed, - 'params': {'icon': icon_path('trustedcoin-wizard.png')}, + 'params': {'icon': self.icon_path('trustedcoin-wizard.png')}, }, 'trustedcoin_keep_disable': { 'gui': WCKeepDisable, - 'params': {'icon': icon_path('trustedcoin-wizard.png')}, + 'params': {'icon': self.icon_path('trustedcoin-wizard.png')}, }, 'trustedcoin_tos': { 'gui': WCTerms, - 'params': {'icon': icon_path('trustedcoin-wizard.png')}, + 'params': {'icon': self.icon_path('trustedcoin-wizard.png')}, }, 'trustedcoin_keystore_unlock': { 'gui': WCKeystorePassword, - 'params': {'icon': icon_path('trustedcoin-wizard.png')}, + 'params': {'icon': self.icon_path('trustedcoin-wizard.png')}, }, 'trustedcoin_show_confirm_otp': { 'gui': WCShowConfirmOTP, - 'params': {'icon': icon_path('trustedcoin-wizard.png')}, + 'params': {'icon': self.icon_path('trustedcoin-wizard.png')}, } } wizard.navmap_merge(views) @@ -279,7 +283,7 @@ class Plugin(TrustedCoinPlugin): }, 'trustedcoin_create_ext': { 'gui': WCEnterExt, - 'params': {'icon': icon_path('trustedcoin-wizard.png')}, + 'params': {'icon': self.icon_path('trustedcoin-wizard.png')}, 'next': 'trustedcoin_confirm_seed', }, 'trustedcoin_confirm_seed': { @@ -287,7 +291,7 @@ class Plugin(TrustedCoinPlugin): }, 'trustedcoin_confirm_ext': { 'gui': WCConfirmExt, - 'params': {'icon': icon_path('trustedcoin-wizard.png')}, + 'params': {'icon': self.icon_path('trustedcoin-wizard.png')}, 'next': 'trustedcoin_tos', }, 'trustedcoin_have_seed': { @@ -295,7 +299,7 @@ class Plugin(TrustedCoinPlugin): }, 'trustedcoin_have_ext': { 'gui': WCEnterExt, - 'params': {'icon': icon_path('trustedcoin-wizard.png')}, + 'params': {'icon': self.icon_path('trustedcoin-wizard.png')}, 'next': 'trustedcoin_keep_disable', }, } @@ -305,7 +309,7 @@ class Plugin(TrustedCoinPlugin): ext_online = { 'trustedcoin_continue_online': { 'gui': WCContinueOnline, - 'params': {'icon': icon_path('trustedcoin-wizard.png')}, + 'params': {'icon': self.icon_path('trustedcoin-wizard.png')}, 'next': lambda d: 'trustedcoin_tos' if d['trustedcoin_go_online'] else 'wallet_password', 'accept': self.on_continue_online, 'last': lambda d: not d['trustedcoin_go_online'] and wizard.is_single_password() diff --git a/electrum/gui/icons/trustedcoin-status-disabled.png b/electrum/plugins/trustedcoin/trustedcoin-status-disabled.png similarity index 100% rename from electrum/gui/icons/trustedcoin-status-disabled.png rename to electrum/plugins/trustedcoin/trustedcoin-status-disabled.png diff --git a/electrum/gui/icons/trustedcoin-status.png b/electrum/plugins/trustedcoin/trustedcoin-status.png similarity index 100% rename from electrum/gui/icons/trustedcoin-status.png rename to electrum/plugins/trustedcoin/trustedcoin-status.png diff --git a/electrum/gui/icons/trustedcoin-wizard.png b/electrum/plugins/trustedcoin/trustedcoin-wizard.png similarity index 100% rename from electrum/gui/icons/trustedcoin-wizard.png rename to electrum/plugins/trustedcoin/trustedcoin-wizard.png