From a080e5130f392b95988e9a82739cd2cf6b0035d6 Mon Sep 17 00:00:00 2001 From: ThomasV Date: Tue, 21 Mar 2023 08:42:30 +0100 Subject: [PATCH] Qt receive_tab: toggle_view_button instead of tabs --- electrum/gui/qt/receive_tab.py | 197 +++++++++++++++------------------ electrum/gui/qt/util.py | 67 ----------- 2 files changed, 92 insertions(+), 172 deletions(-) diff --git a/electrum/gui/qt/receive_tab.py b/electrum/gui/qt/receive_tab.py index a302d7d45..4093e9431 100644 --- a/electrum/gui/qt/receive_tab.py +++ b/electrum/gui/qt/receive_tab.py @@ -73,18 +73,16 @@ class ReceiveTab(QWidget, MessageBoxMixin, Logger): buttons.addWidget(self.create_invoice_button) grid.addLayout(buttons, 4, 0, 1, -1) - self.receive_address_e = QTextEdit() - self.receive_address_help_text = WWLabel('') - vbox = QVBoxLayout() - vbox.addWidget(self.receive_address_help_text) - self.receive_address_help = FramedWidget() - self.receive_address_help.setVisible(False) - self.receive_address_help.setLayout(vbox) - - self.receive_URI_e = QTextEdit() - self.receive_URI_help = WWLabel('') - self.receive_lightning_e = QTextEdit() - self.receive_lightning_help_text = WWLabel('') + self.receive_e = QTextEdit() + self.receive_e.setFont(QFont(MONOSPACE_FONT)) + self.receive_e.setReadOnly(True) + self.receive_e.setContextMenuPolicy(Qt.NoContextMenu) + self.receive_e.setTextInteractionFlags(Qt.NoTextInteraction) + self.receive_e.textChanged.connect(self.update_receive_widgets) + + self.receive_qr = QRCodeWidget(manual_size=True) + + self.receive_help_text = WWLabel('') self.receive_rebalance_button = QPushButton('Rebalance') self.receive_rebalance_button.suggestion = None def on_receive_rebalance(): @@ -103,44 +101,19 @@ class ReceiveTab(QWidget, MessageBoxMixin, Logger): buttons.addWidget(self.receive_rebalance_button) buttons.addWidget(self.receive_swap_button) vbox = QVBoxLayout() - vbox.addWidget(self.receive_lightning_help_text) + vbox.addWidget(self.receive_help_text) vbox.addLayout(buttons) - self.receive_lightning_help = FramedWidget() - self.receive_lightning_help.setVisible(False) - self.receive_lightning_help.setLayout(vbox) - self.receive_address_qr = QRCodeWidget(manual_size=True) - self.receive_URI_qr = QRCodeWidget(manual_size=True) - self.receive_lightning_qr = QRCodeWidget(manual_size=True) - - for e in [self.receive_address_e, self.receive_URI_e, self.receive_lightning_e]: - e.setFont(QFont(MONOSPACE_FONT)) - e.setReadOnly(True) - e.setContextMenuPolicy(Qt.NoContextMenu) - e.setTextInteractionFlags(Qt.NoTextInteraction) - - self.receive_lightning_e.textChanged.connect(self.update_receive_widgets) - - self.receive_address_widget = ReceiveTabWidget(self, - self.receive_address_e, self.receive_address_qr, self.receive_address_help) - self.receive_URI_widget = ReceiveTabWidget(self, - self.receive_URI_e, self.receive_URI_qr, self.receive_URI_help) - self.receive_lightning_widget = ReceiveTabWidget(self, - self.receive_lightning_e, self.receive_lightning_qr, self.receive_lightning_help) - - from .util import VTabWidget - self.receive_tabs = VTabWidget() - self.receive_tabs.setMinimumHeight(ReceiveTabWidget.min_size.height()) - - #self.receive_tabs.setMinimumHeight(ReceiveTabWidget.min_size.height() + 4) # for margins - self.receive_tabs.addTab(self.receive_URI_widget, read_QIcon("link.png"), _('URI')) - self.receive_tabs.addTab(self.receive_address_widget, read_QIcon("bitcoin.png"), _('Address')) - self.receive_tabs.addTab(self.receive_lightning_widget, read_QIcon("lightning.png"), _('Lightning')) - self.receive_tabs.setCurrentIndex(self.config.get('receive_tabs_index', 0)) - self.receive_tabs.currentChanged.connect(self.on_tab_changed) - receive_tabs_sp = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) - receive_tabs_sp.setRetainSizeWhenHidden(True) - self.receive_tabs.setSizePolicy(receive_tabs_sp) - self.receive_tabs.setVisible(False) + self.receive_help_widget = FramedWidget() + self.receive_help_widget.setVisible(False) + self.receive_help_widget.setLayout(vbox) + + self.receive_widget = ReceiveWidget( + self, self.receive_e, self.receive_qr, self.receive_help_widget) + + receive_widget_sp = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.MinimumExpanding) + receive_widget_sp.setRetainSizeWhenHidden(True) + self.receive_widget.setSizePolicy(receive_widget_sp) + self.receive_widget.setVisible(False) self.receive_requests_label = QLabel(_('Requests')) # with QDarkStyle, this label may partially cover the qrcode widget. @@ -150,12 +123,20 @@ class ReceiveTab(QWidget, MessageBoxMixin, Logger): self.request_list = RequestList(self) # toolbar self.toolbar, menu = self.request_list.create_toolbar_with_menu('') + self.toggle_qr_button = QPushButton('') self.toggle_qr_button.setIcon(read_QIcon('qrcode.png')) self.toggle_qr_button.setToolTip(_('Switch between text and QR code view')) self.toggle_qr_button.clicked.connect(self.toggle_receive_qr) self.toggle_qr_button.setEnabled(False) self.toolbar.insertWidget(2, self.toggle_qr_button) + + self.toggle_view_button = QPushButton('') + self.toggle_view_button.setToolTip(_('switch between view')) + self.toggle_view_button.clicked.connect(self.toggle_view) + self.toggle_view_button.setEnabled(False) + self.update_view_button() + self.toolbar.insertWidget(2, self.toggle_view_button) # menu menu.addConfig( _('Add on-chain fallback to lightning requests'), 'bolt11_fallback', True, @@ -177,7 +158,7 @@ class ReceiveTab(QWidget, MessageBoxMixin, Logger): hbox = QHBoxLayout() hbox.addLayout(vbox_g) hbox.addStretch() - hbox.addWidget(self.receive_tabs) + hbox.addWidget(self.receive_widget) self.searchable_list = self.request_list vbox = QVBoxLayout(self) @@ -220,17 +201,33 @@ class ReceiveTab(QWidget, MessageBoxMixin, Logger): self.wallet.lnworker.clear_invoices_cache() self.update_current_request() - def on_tab_changed(self, i): + def update_view_button(self): + i = self.config.get('receive_tabs_index', 0) + if i == 0: + icon, text = read_QIcon("link.png"), _('Bitcoin URI') + elif i == 1: + icon, text = read_QIcon("bitcoin.png"), _('Address') + elif i == 2: + icon, text = read_QIcon("lightning.png"), _('Lightning') + self.toggle_view_button.setText(text) + self.toggle_view_button.setIcon(icon) + + def toggle_view(self): + i = self.config.get('receive_tabs_index', 0) + i = (i + 1) % (3 if self.wallet.has_lightning() else 2) self.config.set_key('receive_tabs_index', i) - title, data = self.get_tab_data(i) + self.update_current_request() + self.update_view_button() + + def on_tab_changed(self): + text, data, help_text, title = self.get_tab_data() self.window.do_copy(data, title=title) self.update_receive_qr_window() def do_copy(self, e): if e.button() != Qt.LeftButton: return - i = self.receive_tabs.currentIndex() - title, data = self.get_tab_data(i) + text, data, help_text, title = self.get_tab_data() self.window.do_copy(data, title=title) def toggle_receive_qr(self): @@ -240,75 +237,59 @@ class ReceiveTab(QWidget, MessageBoxMixin, Logger): def update_receive_widgets(self): b = self.config.get('receive_qr_visible', False) - self.receive_URI_widget.update_visibility(b) - self.receive_address_widget.update_visibility(b) - self.receive_lightning_widget.update_visibility(b) + self.receive_widget.update_visibility(b) def update_current_request(self): key = self.request_list.get_current_key() req = self.wallet.get_request(key) if key else None if req is None: - self.receive_URI_e.setText('') - self.receive_lightning_e.setText('') - self.receive_address_e.setText('') + self.receive_e.setText('') return help_texts = self.wallet.get_help_texts_for_receive_request(req) - addr = (req.get_address() or '') if not help_texts.address_is_error else '' - URI = (self.wallet.get_request_URI(req) or '') if not help_texts.URI_is_error else '' - lnaddr = self.wallet.get_bolt11_invoice(req) if not help_texts.ln_is_error else '' - address_help = help_texts.address_help - URI_help = help_texts.URI_help - ln_help = help_texts.ln_help + self.addr = (req.get_address() or '') if not help_texts.address_is_error else '' + self.URI = (self.wallet.get_request_URI(req) or '') if not help_texts.URI_is_error else '' + self.lnaddr = self.wallet.get_bolt11_invoice(req) if not help_texts.ln_is_error else '' + self.address_help = help_texts.address_help + self.URI_help = help_texts.URI_help + self.ln_help = help_texts.ln_help can_rebalance = help_texts.can_rebalance() can_swap = help_texts.can_swap() self.receive_rebalance_button.suggestion = help_texts.ln_rebalance_suggestion self.receive_swap_button.suggestion = help_texts.ln_swap_suggestion - self.receive_rebalance_button.setVisible(can_rebalance) self.receive_swap_button.setVisible(can_swap) self.receive_rebalance_button.setEnabled(can_rebalance and self.window.num_tasks() == 0) self.receive_swap_button.setEnabled(can_swap and self.window.num_tasks() == 0) - icon_name = "lightning.png" if lnaddr else "lightning_disconnected.png" - self.receive_tabs.setTabIcon(2, read_QIcon(icon_name)) - # encode lightning invoices as uppercase so QR encoding can use - # alphanumeric mode; resulting in smaller QR codes - self.receive_address_e.setText(addr) - self.receive_address_qr.setData(addr) - self.receive_address_help_text.setText(address_help) - self.receive_URI_e.setText(URI) - self.receive_URI_qr.setData(URI) - self.receive_URI_help.setText(URI_help) - self.receive_lightning_e.setText(lnaddr) # TODO maybe prepend "lightning:" ?? - self.receive_lightning_help_text.setText(ln_help) - self.receive_lightning_qr.setData(lnaddr.upper()) - def update_warnings(text_e, qr_e, warning_text): - for w in [text_e, qr_e]: - w.setEnabled(bool(text_e.toPlainText()) and not warning_text) - w.setToolTip(warning_text) - update_warnings(self.receive_address_e, self.receive_address_qr, address_help) - update_warnings(self.receive_URI_e, self.receive_URI_qr, URI_help) - update_warnings(self.receive_lightning_e, self.receive_lightning_qr, ln_help) + text, data, help_text, title = self.get_tab_data() + self.receive_e.setText(text) + self.receive_qr.setData(data) + self.receive_help_text.setText(help_text) + for w in [self.receive_e, self.receive_qr]: + w.setEnabled(bool(text) and not help_text) + w.setToolTip(help_text) # macOS hack (similar to #4777) - self.receive_lightning_e.repaint() - self.receive_URI_e.repaint() - self.receive_address_e.repaint() + self.receive_e.repaint() # always show - self.receive_tabs.setVisible(True) + self.receive_widget.setVisible(True) self.toggle_qr_button.setEnabled(True) + self.toggle_view_button.setEnabled(True) self.update_receive_qr_window() - def get_tab_data(self, i): + def get_tab_data(self): + i = self.config.get('receive_tabs_index', 0) if i == 0: - return _('Bitcoin URI'), self.receive_URI_e.toPlainText() + out = self.URI, self.URI, self.URI_help, _('Bitcoin URI') elif i == 1: - return _('Address'), self.receive_address_e.toPlainText() - else: - return _('Lightning Request'), self.receive_lightning_e.toPlainText() + out = self.addr, self.addr, self.address_help, _('Address') + elif i == 2: + # encode lightning invoices as uppercase so QR encoding can use + # alphanumeric mode; resulting in smaller QR codes + out = self.lnaddr, self.lnaddr.upper(), self.ln_help, _('Lightning Request') + return out def update_receive_qr_window(self): if self.window.qr_window and self.window.qr_window.isVisible(): - i = self.receive_tabs.currentIndex() - title, data = self.get_tab_data(i) + text, data, help_text, title = self.get_tab_data() if i == 2: data = data.upper() self.window.qr_window.qrw.setData(data) @@ -347,7 +328,7 @@ class ReceiveTab(QWidget, MessageBoxMixin, Logger): self.receive_amount_e.setText('') self.receive_message_e.setText('') # copy current tab to clipboard - self.on_tab_changed(self.receive_tabs.currentIndex()) + self.on_tab_changed() def get_bitcoin_address_for_request(self, amount) -> Optional[str]: addr = self.wallet.get_unused_address() @@ -369,25 +350,25 @@ class ReceiveTab(QWidget, MessageBoxMixin, Logger): return addr def do_clear(self): - self.receive_address_e.setText('') - self.receive_URI_e.setText('') - self.receive_lightning_e.setText('') - self.receive_tabs.setVisible(False) + self.receive_e.setText('') + self.receive_widget.setVisible(False) self.toggle_qr_button.setEnabled(False) + self.toggle_view_button.setEnabled(False) self.receive_message_e.setText('') self.receive_amount_e.setAmount(None) self.request_list.clearSelection() -class ReceiveTabWidget(QWidget): +class ReceiveWidget(QWidget): min_size = QSize(200, 200) def __init__(self, receive_tab: 'ReceiveTab', textedit: QWidget, qr: QWidget, help_widget: QWidget): + QWidget.__init__(self) self.textedit = textedit self.qr = qr self.help_widget = help_widget - QWidget.__init__(self) + self.setMinimumSize(self.min_size) for w in [textedit, qr, help_widget]: w.setMinimumSize(self.min_size) @@ -416,6 +397,12 @@ class ReceiveTabWidget(QWidget): self.textedit.setVisible(False) self.qr.setVisible(False) + def resizeEvent(self, e): + # keep square aspect ratio when resized + size = e.size() + w = size.height() + self.setFixedWidth(w) + return super().resizeEvent(e) class FramedWidget(QFrame): def __init__(self): diff --git a/electrum/gui/qt/util.py b/electrum/gui/qt/util.py index a03a78cb5..63db8c344 100644 --- a/electrum/gui/qt/util.py +++ b/electrum/gui/qt/util.py @@ -1263,73 +1263,6 @@ class ImageGraphicsEffect(QObject): return result -class SquareTabWidget(QtWidgets.QStackedWidget): - def resizeEvent(self, e): - # keep square aspect ratio when resized - size = e.size() - w = size.height() - self.setFixedWidth(w) - return super().resizeEvent(e) - - -class VTabWidget(QWidget): - """QtWidgets.QTabWidget alternative with "West" tab positions and horizontal tab-text.""" - def __init__(self): - QWidget.__init__(self) - - hbox = QHBoxLayout() - self.setLayout(hbox) - hbox.setContentsMargins(0, 0, 0, 0) - hbox.setSpacing(0) - - self._tabs_vbox = tabs_vbox = QVBoxLayout() - self._tab_btns = [] # type: List[QPushButton] - tabs_vbox.setContentsMargins(0, 0, 0, 0) - tabs_vbox.setSpacing(0) - - _tabs_vbox_outer_w = QWidget() - _tabs_vbox_outer = QVBoxLayout() - _tabs_vbox_outer_w.setLayout(_tabs_vbox_outer) - _tabs_vbox_outer_w.setSizePolicy(QSizePolicy(QSizePolicy.Maximum, _tabs_vbox_outer_w.sizePolicy().verticalPolicy())) - _tabs_vbox_outer.setContentsMargins(0, 0, 0, 0) - _tabs_vbox_outer.setSpacing(0) - _tabs_vbox_outer.addLayout(tabs_vbox) - _tabs_vbox_outer.addStretch(1) - - self.content_w = content_w = SquareTabWidget() - content_w.setStyleSheet("SquareTabWidget {padding:0px; }") - hbox.addStretch(1) - hbox.addWidget(_tabs_vbox_outer_w) - hbox.addWidget(content_w) - - self.currentChanged = content_w.currentChanged - self.currentIndex = content_w.currentIndex - - def addTab(self, widget: QWidget, icon: QIcon, text: str): - btn = QPushButton(icon, text) - btn.setStyleSheet("QPushButton { text-align: left; }") - btn.setFocusPolicy(QtCore.Qt.NoFocus) - btn.setCheckable(True) - btn.setSizePolicy(QSizePolicy.Preferred, btn.sizePolicy().verticalPolicy()) - - def on_btn_click(): - btn.setChecked(True) - for btn2 in self._tab_btns: - if btn2 != btn: - btn2.setChecked(False) - self.content_w.setCurrentIndex(idx) - btn.clicked.connect(on_btn_click) - idx = len(self._tab_btns) - self._tab_btns.append(btn) - - self._tabs_vbox.addWidget(btn) - self.content_w.addWidget(widget) - - def setTabIcon(self, idx: int, icon: QIcon): - self._tab_btns[idx].setIcon(icon) - - def setCurrentIndex(self, idx: int): - self._tab_btns[idx].click() class QtEventListener(EventListener):