Browse Source

qt: PayToEdit and OverlayControlMixin: move around input buttons

patch-4
SomberNight 3 years ago
parent
commit
955986d024
No known key found for this signature in database GPG Key ID: B33B5F232C6271E9
  1. BIN
      electrum/gui/icons/menu_vertical.png
  2. BIN
      electrum/gui/icons/menu_vertical_white.png
  3. BIN
      electrum/gui/icons/picture_in_picture.png
  4. 46
      electrum/gui/qt/qrtextedit.py
  5. 6
      electrum/gui/qt/transaction_dialog.py
  6. 246
      electrum/gui/qt/util.py

BIN
electrum/gui/icons/menu_vertical.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 997 B

BIN
electrum/gui/icons/menu_vertical_white.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

BIN
electrum/gui/icons/picture_in_picture.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

46
electrum/gui/qt/qrtextedit.py

@ -1,10 +1,12 @@
from functools import partial
from typing import Callable
from electrum.i18n import _
from electrum.plugin import run_hook
from electrum.simple_config import SimpleConfig
from .util import ButtonsTextEdit, MessageBoxMixin
from .util import ButtonsTextEdit, MessageBoxMixin, ColorScheme, read_QIcon
from .util import get_iconname_camera, get_iconname_qrcode
class ShowQRTextEdit(ButtonsTextEdit):
@ -31,15 +33,41 @@ class ScanQRTextEdit(ButtonsTextEdit, MessageBoxMixin):
):
ButtonsTextEdit.__init__(self, text)
self.setReadOnly(False)
self.add_file_input_button(config=config, show_error=self.show_error, setText=setText)
self.add_qr_input_button(config=config, show_error=self.show_error, allow_multi=allow_multi, setText=setText)
input_qr_from_camera = partial(
self.input_qr_from_camera,
config=config,
allow_multi=allow_multi,
show_error=self.show_error,
setText=setText,
)
self.on_qr_from_camera_input_btn = input_qr_from_camera
input_qr_from_screenshot = partial(
self.input_qr_from_screenshot,
allow_multi=allow_multi,
show_error=self.show_error,
setText=setText,
)
self.on_qr_from_screenshot_input_btn = input_qr_from_screenshot
input_file = partial(self.input_file, config=config, show_error=self.show_error, setText=setText)
self.add_menu_button(
options=[
("picture_in_picture.png", _("Read QR code from screen"), input_qr_from_screenshot),
("file.png", _("Read file"), input_file),
],
)
self.add_qr_input_from_camera_button(config=config, show_error=self.show_error, allow_multi=allow_multi, setText=setText)
run_hook('scan_text_edit', self)
def contextMenuEvent(self, e):
m = self.createStandardContextMenu()
m.addSeparator()
m.addAction(_("Read QR code from camera"), self.on_qr_from_camera_input_btn)
m.addAction(_("Read QR code from screen"), self.on_qr_from_screenshot_input_btn)
m.addAction(read_QIcon(get_iconname_camera()), _("Read QR code from camera"), self.on_qr_from_camera_input_btn)
m.addAction(read_QIcon("picture_in_picture.png"), _("Read QR code from screen"), self.on_qr_from_screenshot_input_btn)
m.exec_(e.globalPos())
@ -48,7 +76,7 @@ class ScanShowQRTextEdit(ButtonsTextEdit, MessageBoxMixin):
def __init__(self, text="", allow_multi: bool = False, *, config: SimpleConfig):
ButtonsTextEdit.__init__(self, text)
self.setReadOnly(False)
self.add_qr_input_button(config=config, show_error=self.show_error, allow_multi=allow_multi)
self.add_qr_input_combined_button(config=config, show_error=self.show_error, allow_multi=allow_multi)
self.add_qr_show_button(config=config)
run_hook('scan_text_edit', self)
run_hook('show_text_edit', self)
@ -56,7 +84,7 @@ class ScanShowQRTextEdit(ButtonsTextEdit, MessageBoxMixin):
def contextMenuEvent(self, e):
m = self.createStandardContextMenu()
m.addSeparator()
m.addAction(_("Read QR code from camera"), self.on_qr_from_camera_input_btn)
m.addAction(_("Read QR code from screen"), self.on_qr_from_screenshot_input_btn)
m.addAction(_("Show as QR code"), self.on_qr_show_btn)
m.addAction(read_QIcon(get_iconname_camera()), _("Read QR code from camera"), self.on_qr_from_camera_input_btn)
m.addAction(read_QIcon("picture_in_picture.png"), _("Read QR code from screen"), self.on_qr_from_screenshot_input_btn)
m.addAction(read_QIcon(get_iconname_qrcode()), _("Show as QR code"), self.on_qr_show_btn)
m.exec_(e.globalPos())

6
electrum/gui/qt/transaction_dialog.py

@ -53,7 +53,8 @@ from .util import (MessageBoxMixin, read_QIcon, Buttons, icon_path,
char_width_in_lineedit, TRANSACTION_FILE_EXTENSION_FILTER_SEPARATE,
TRANSACTION_FILE_EXTENSION_FILTER_ONLY_COMPLETE_TX,
TRANSACTION_FILE_EXTENSION_FILTER_ONLY_PARTIAL_TX,
BlockingWaitingDialog, getSaveFileName, ColorSchemeItem)
BlockingWaitingDialog, getSaveFileName, ColorSchemeItem,
get_iconname_qrcode)
from .fee_slider import FeeSlider, FeeComboBox
from .confirm_tx_dialog import TxEditor
@ -273,8 +274,7 @@ class BaseTxDialog(QDialog, MessageBoxMixin):
action.triggered.connect(lambda: self.copy_to_clipboard(tx=gettx()))
menu.addAction(action)
qr_icon = "qrcode_white.png" if ColorScheme.dark_scheme else "qrcode.png"
action = QAction(read_QIcon(qr_icon), _("Show as QR code"), self)
action = QAction(read_QIcon(get_iconname_qrcode()), _("Show as QR code"), self)
action.triggered.connect(lambda: self.show_qr(tx=gettx()))
menu.addAction(action)

246
electrum/gui/qt/util.py

@ -10,7 +10,7 @@ import webbrowser
from decimal import Decimal
from functools import partial, lru_cache, wraps
from typing import (NamedTuple, Callable, Optional, TYPE_CHECKING, Union, List, Dict, Any,
Sequence, Iterable)
Sequence, Iterable, Tuple)
from PyQt5.QtGui import (QFont, QColor, QCursor, QPixmap, QStandardItem, QImage,
QPalette, QIcon, QFontMetrics, QShowEvent, QPainter, QHelpEvent)
@ -845,6 +845,14 @@ class MySortModel(QSortFilterProxyModel):
return v1 < v2
def get_iconname_qrcode() -> str:
return "qrcode_white.png" if ColorScheme.dark_scheme else "qrcode.png"
def get_iconname_camera() -> str:
return "camera_white.png" if ColorScheme.dark_scheme else "camera_dark.png"
class OverlayControlMixin:
STYLE_SHEET_COMMON = '''
QPushButton { border-width: 1px; padding: 0px; margin: 0px; }
@ -916,13 +924,11 @@ class OverlayControlMixin:
*,
setText: Callable[[str], None] = None,
):
if setText is None:
setText = self.setText
def on_paste():
app = QApplication.instance()
setText(app.clipboard().text())
self.addButton("copy.png", on_paste, _("Paste from clipboard"))
input_paste_from_clipboard = partial(
self.input_paste_from_clipboard,
setText=setText,
)
self.addButton("copy.png", input_paste_from_clipboard, _("Paste from clipboard"))
def add_qr_show_button(self, *, config: 'SimpleConfig', title: Optional[str] = None):
if title is None:
@ -943,12 +949,44 @@ class OverlayControlMixin:
config=config,
).exec_()
icon = "qrcode_white.png" if ColorScheme.dark_scheme else "qrcode.png"
self.addButton(icon, qr_show, _("Show as QR code"))
self.addButton(get_iconname_qrcode(), qr_show, _("Show as QR code"))
# side-effect: we export this method:
self.on_qr_show_btn = qr_show
def add_qr_input_button(
def add_qr_input_combined_button(
self,
*,
config: 'SimpleConfig',
allow_multi: bool = False,
show_error: Callable[[str], None],
setText: Callable[[str], None] = None,
):
input_qr_from_camera = partial(
self.input_qr_from_camera,
config=config,
allow_multi=allow_multi,
show_error=show_error,
setText=setText,
)
input_qr_from_screenshot = partial(
self.input_qr_from_screenshot,
allow_multi=allow_multi,
show_error=show_error,
setText=setText,
)
self.add_menu_button(
icon=get_iconname_camera(),
tooltip=_("Read QR code"),
options=[
(get_iconname_camera(), _("Read QR code from camera"), input_qr_from_camera),
("picture_in_picture.png", _("Read QR code from screen"), input_qr_from_screenshot),
],
)
# side-effect: we export these methods:
self.on_qr_from_camera_input_btn = input_qr_from_camera
self.on_qr_from_screenshot_input_btn = input_qr_from_screenshot
def add_qr_input_from_camera_button(
self,
*,
config: 'SimpleConfig',
@ -956,90 +994,148 @@ class OverlayControlMixin:
show_error: Callable[[str], None],
setText: Callable[[str], None] = None,
):
input_qr_from_camera = partial(
self.input_qr_from_camera,
config=config,
allow_multi=allow_multi,
show_error=show_error,
setText=setText,
)
self.addButton(get_iconname_camera(), input_qr_from_camera, _("Read QR code from camera"))
# side-effect: we export these methods:
self.on_qr_from_camera_input_btn = input_qr_from_camera
def add_file_input_button(
self,
*,
config: 'SimpleConfig',
show_error: Callable[[str], None],
setText: Callable[[str], None] = None,
) -> None:
input_file = partial(
self.input_file,
config=config,
show_error=show_error,
setText=setText,
)
self.addButton("file.png", input_file, _("Read file"))
def add_menu_button(
self,
*,
options: Sequence[Tuple[Optional[str], str, Callable[[], None]]], # list of (icon, text, cb)
icon: Optional[str] = None,
tooltip: Optional[str] = None,
):
if icon is None:
icon = "menu_vertical_white.png" if ColorScheme.dark_scheme else "menu_vertical.png"
if tooltip is None:
tooltip = _("Other options")
btn = self.addButton(icon, lambda: None, tooltip)
menu = QMenu()
for opt_icon, opt_text, opt_cb in options:
if opt_icon is None:
menu.addAction(opt_text, opt_cb)
else:
menu.addAction(read_QIcon(opt_icon), opt_text, opt_cb)
btn.setMenu(menu)
def input_qr_from_camera(
self,
*,
config: 'SimpleConfig',
allow_multi: bool = False,
show_error: Callable[[str], None],
setText: Callable[[str], None] = None,
) -> None:
if setText is None:
setText = self.setText
def qr_from_camera_input() -> None:
def cb(success: bool, error: str, data):
if not success:
if error:
show_error(error)
return
if not data:
data = ''
if allow_multi:
new_text = self.text() + data + '\n'
else:
new_text = data
setText(new_text)
from .qrreader import scan_qrcode
scan_qrcode(parent=self, config=config, callback=cb)
def qr_from_screenshot_input() -> None:
from .qrreader import scan_qr_from_image
scanned_qr = None
for screen in QApplication.instance().screens():
try:
scan_result = scan_qr_from_image(screen.grabWindow(0).toImage())
except MissingQrDetectionLib as e:
show_error(_("Unable to scan image.") + "\n" + repr(e))
return
if len(scan_result) > 0:
if (scanned_qr is not None) or len(scan_result) > 1:
show_error(_("More than one QR code was found on the screen."))
return
scanned_qr = scan_result
if scanned_qr is None:
show_error(_("No QR code was found on the screen."))
def cb(success: bool, error: str, data):
if not success:
if error:
show_error(error)
return
data = scanned_qr[0].data
if not data:
data = ''
if allow_multi:
new_text = self.text() + data + '\n'
else:
new_text = data
setText(new_text)
icon = "camera_white.png" if ColorScheme.dark_scheme else "camera_dark.png"
btn = self.addButton(icon, lambda: None, _("Read QR code"))
menu = QMenu()
menu.addAction(_("Read QR code from camera"), qr_from_camera_input)
menu.addAction(_("Read QR code from screen"), qr_from_screenshot_input)
btn.setMenu(menu)
# side-effect: we export these methods:
self.on_qr_from_camera_input_btn = qr_from_camera_input
self.on_qr_from_screenshot_input_btn = qr_from_screenshot_input
from .qrreader import scan_qrcode
scan_qrcode(parent=self, config=config, callback=cb)
def add_file_input_button(
def input_qr_from_screenshot(
self,
*,
config: 'SimpleConfig',
allow_multi: bool = False,
show_error: Callable[[str], None],
setText: Callable[[str], None] = None,
) -> None:
if setText is None:
setText = self.setText
def file_input():
fileName = getOpenFileName(
parent=self,
title='select file',
config=config,
)
if not fileName:
from .qrreader import scan_qr_from_image
scanned_qr = None
for screen in QApplication.instance().screens():
try:
scan_result = scan_qr_from_image(screen.grabWindow(0).toImage())
except MissingQrDetectionLib as e:
show_error(_("Unable to scan image.") + "\n" + repr(e))
return
if len(scan_result) > 0:
if (scanned_qr is not None) or len(scan_result) > 1:
show_error(_("More than one QR code was found on the screen."))
return
scanned_qr = scan_result
if scanned_qr is None:
show_error(_("No QR code was found on the screen."))
return
data = scanned_qr[0].data
if allow_multi:
new_text = self.text() + data + '\n'
else:
new_text = data
setText(new_text)
def input_file(
self,
*,
config: 'SimpleConfig',
show_error: Callable[[str], None],
setText: Callable[[str], None] = None,
) -> None:
if setText is None:
setText = self.setText
fileName = getOpenFileName(
parent=self,
title='select file',
config=config,
)
if not fileName:
return
try:
try:
try:
with open(fileName, "r") as f:
data = f.read()
except UnicodeError as e:
with open(fileName, "rb") as f:
data = f.read()
data = data.hex()
except BaseException as e:
show_error(_('Error opening file') + ':\n' + repr(e))
else:
setText(data)
with open(fileName, "r") as f:
data = f.read()
except UnicodeError as e:
with open(fileName, "rb") as f:
data = f.read()
data = data.hex()
except BaseException as e:
show_error(_('Error opening file') + ':\n' + repr(e))
else:
setText(data)
self.addButton("file.png", file_input, _("Read file"))
def input_paste_from_clipboard(
self,
*,
setText: Callable[[str], None] = None,
) -> None:
if setText is None:
setText = self.setText
app = QApplication.instance()
setText(app.clipboard().text())
class ButtonsLineEdit(OverlayControlMixin, QLineEdit):

Loading…
Cancel
Save