def setup_dialog(self, window): self.wallet = window.parent().wallet self.update_wallet_name(self.wallet) self.user_input = False self.d = WindowModalDialog(window, "Setup Dialog") self.d.setMinimumWidth(500) self.d.setMinimumHeight(210) self.d.setMaximumHeight(320) self.d.setContentsMargins(11,11,1,1) self.hbox = QHBoxLayout(self.d) vbox = QVBoxLayout() logo = QLabel() self.hbox.addWidget(logo) logo.setPixmap(QPixmap(icon_path('revealer.png'))) logo.setAlignment(Qt.AlignLeft) self.hbox.addSpacing(16) vbox.addWidget(WWLabel("<b>"+_("Revealer Visual Cryptography Plugin")+"</b><br><br>" +_("To encrypt a secret, first create or load noise.")+"<br/>")) vbox.addSpacing(7) bcreate = QPushButton(_("Create a new Revealer")) bcreate.setMaximumWidth(181) bcreate.setDefault(True) vbox.addWidget(bcreate, Qt.AlignCenter) self.load_noise = ScanQRTextEdit(config=self.config) self.load_noise.setTabChangesFocus(True) self.load_noise.textChanged.connect(self.on_edit) self.load_noise.setMaximumHeight(33) self.hbox.addLayout(vbox) vbox.addWidget(WWLabel(_("or type an existing revealer code below and click 'next':"))) vbox.addWidget(self.load_noise) vbox.addSpacing(3) self.next_button = QPushButton(_("Next"), self.d) self.next_button.setEnabled(False) vbox.addLayout(Buttons(self.next_button)) self.next_button.clicked.connect(self.d.close) self.next_button.clicked.connect(partial(self.cypherseed_dialog, window)) def mk_digital(): try: self.make_digital(self.d) except Exception: self.logger.exception('') else: self.cypherseed_dialog(window) bcreate.clicked.connect(mk_digital) return bool(self.d.exec_())
def __init__(self, parent): super(CharacterDialog, self).__init__(parent) self.setWindowTitle(_("KeepKey Seed Recovery")) self.character_pos = 0 self.word_pos = 0 self.loop = QEventLoop() self.word_help = QLabel() self.char_buttons = [] vbox = QVBoxLayout(self) vbox.addWidget(WWLabel(CHARACTER_RECOVERY)) hbox = QHBoxLayout() hbox.addWidget(self.word_help) for i in range(4): char_button = CharacterButton('*') char_button.setMaximumWidth(36) self.char_buttons.append(char_button) hbox.addWidget(char_button) self.accept_button = CharacterButton(_("Accept Word")) self.accept_button.clicked.connect(partial(self.process_key, 32)) self.rejected.connect(partial(self.loop.exit, 1)) hbox.addWidget(self.accept_button) hbox.addStretch(1) vbox.addLayout(hbox) self.finished_button = QPushButton(_("Seed Entered")) self.cancel_button = QPushButton(_("Cancel")) self.finished_button.clicked.connect(partial(self.process_key, Qt.Key_Return)) self.cancel_button.clicked.connect(self.rejected) buttons = Buttons(self.finished_button, self.cancel_button) vbox.addSpacing(40) vbox.addLayout(buttons) self.refresh() self.show()
def __init__(self, parent): super(MatrixDialog, self).__init__(parent) self.setWindowTitle(_("Trezor Matrix Recovery")) self.num = 9 self.loop = QEventLoop() vbox = QVBoxLayout(self) vbox.addWidget(WWLabel(MATRIX_RECOVERY)) grid = QGridLayout() grid.setSpacing(0) self.char_buttons = [] for y in range(3): for x in range(3): button = QPushButton('?') button.clicked.connect( partial(self.process_key, ord('1') + y * 3 + x)) grid.addWidget(button, 3 - y, x) self.char_buttons.append(button) vbox.addLayout(grid) self.backspace_button = QPushButton("<=") self.backspace_button.clicked.connect( partial(self.process_key, Qt.Key_Backspace)) self.cancel_button = QPushButton(_("Cancel")) self.cancel_button.clicked.connect( partial(self.process_key, Qt.Key_Escape)) buttons = Buttons(self.backspace_button, self.cancel_button) vbox.addSpacing(40) vbox.addLayout(buttons) self.refresh() self.show()
def passphrase_dialog(self, msg, confirm): # If confirm is true, require the user to enter the passphrase twice parent = self.top_level_window() d = WindowModalDialog(parent, _("Enter Passphrase")) if confirm: OK_button = OkButton(d) playout = PasswordLayout(msg=msg, kind=PW_PASSPHRASE, OK_button=OK_button) vbox = QVBoxLayout() vbox.addLayout(playout.layout()) vbox.addLayout(Buttons(CancelButton(d), OK_button)) d.setLayout(vbox) passphrase = playout.new_password() if d.exec_() else None else: pw = PasswordLineEdit() pw.setMinimumWidth(200) vbox = QVBoxLayout() vbox.addWidget(WWLabel(msg)) vbox.addWidget(pw) vbox.addLayout(Buttons(CancelButton(d), OkButton(d))) d.setLayout(vbox) passphrase = pw.text() if d.exec_() else None self.passphrase = passphrase self.done.set()
def cypherseed_dialog(self, window): self.warn_old_revealer() d = WindowModalDialog(window, "Encryption Dialog") d.setMinimumWidth(500) d.setMinimumHeight(210) d.setMaximumHeight(450) d.setContentsMargins(11, 11, 1, 1) self.c_dialog = d hbox = QHBoxLayout(d) self.vbox = QVBoxLayout() logo = QLabel() hbox.addWidget(logo) logo.setPixmap(QPixmap(icon_path('revealer.png'))) logo.setAlignment(Qt.AlignLeft) hbox.addSpacing(16) self.vbox.addWidget( WWLabel("<b>" + _("Revealer Secret Backup Plugin") + "</b><br>" + _("Ready to encrypt for revealer {}").format( self.versioned_seed.version + '_' + self.versioned_seed.checksum))) self.vbox.addSpacing(11) hbox.addLayout(self.vbox) grid = QGridLayout() self.vbox.addLayout(grid) cprint = QPushButton(_("Encrypt {}'s seed").format(self.wallet_name)) cprint.setMaximumWidth(250) cprint.clicked.connect(partial(self.seed_img, True)) self.vbox.addWidget(cprint) self.vbox.addSpacing(1) self.vbox.addWidget( WWLabel("<b>" + _("OR") + "</b> " + _("type a custom alphanumerical secret below:"))) self.text = ScanQRTextEdit() self.text.setTabChangesFocus(True) self.text.setMaximumHeight(70) self.text.textChanged.connect(self.customtxt_limits) self.vbox.addWidget(self.text) self.char_count = WWLabel("") self.char_count.setAlignment(Qt.AlignRight) self.vbox.addWidget(self.char_count) self.max_chars = WWLabel( "<font color='red'>" + _("This version supports a maximum of {} characters.").format( self.MAX_PLAINTEXT_LEN) + "</font>") self.vbox.addWidget(self.max_chars) self.max_chars.setVisible(False) self.ctext = QPushButton(_("Encrypt custom secret")) self.ctext.clicked.connect(self.t) self.vbox.addWidget(self.ctext) self.ctext.setEnabled(False) self.vbox.addSpacing(11) self.vbox.addLayout(Buttons(CloseButton(d))) return bool(d.exec_())
def request_safe_t_init_settings(self, wizard, method, device): vbox = QVBoxLayout() next_enabled = True label = QLabel(_("Enter a label to name your device:")) name = QLineEdit() hl = QHBoxLayout() hl.addWidget(label) hl.addWidget(name) hl.addStretch(1) vbox.addLayout(hl) def clean_text(widget): text = widget.toPlainText().strip() return ' '.join(text.split()) if method in [TIM_NEW, TIM_RECOVER]: gb = QGroupBox() hbox1 = QHBoxLayout() gb.setLayout(hbox1) vbox.addWidget(gb) gb.setTitle(_("Select your seed length:")) bg = QButtonGroup() for i, count in enumerate([12, 18, 24]): rb = QRadioButton(gb) rb.setText(_("{:d} words").format(count)) bg.addButton(rb) bg.setId(rb, i) hbox1.addWidget(rb) rb.setChecked(True) cb_pin = QCheckBox(_('Enable PIN protection')) cb_pin.setChecked(True) else: text = QTextEdit() text.setMaximumHeight(60) if method == TIM_MNEMONIC: msg = _("Enter your BIP39 mnemonic:") else: msg = _("Enter the master private key beginning with xprv:") def set_enabled(): from electrum_firo.bip32 import is_xprv wizard.next_button.setEnabled(is_xprv(clean_text(text))) text.textChanged.connect(set_enabled) next_enabled = False vbox.addWidget(QLabel(msg)) vbox.addWidget(text) pin = QLineEdit() pin.setValidator(QRegExpValidator(QRegExp('[1-9]{0,9}'))) pin.setMaximumWidth(100) hbox_pin = QHBoxLayout() hbox_pin.addWidget(QLabel(_("Enter your PIN (digits 1-9):"))) hbox_pin.addWidget(pin) hbox_pin.addStretch(1) if method in [TIM_NEW, TIM_RECOVER]: vbox.addWidget(WWLabel(RECOMMEND_PIN)) vbox.addWidget(cb_pin) else: vbox.addLayout(hbox_pin) passphrase_msg = WWLabel(PASSPHRASE_HELP_SHORT) passphrase_warning = WWLabel(PASSPHRASE_NOT_PIN) passphrase_warning.setStyleSheet("color: red") cb_phrase = QCheckBox(_('Enable passphrases')) cb_phrase.setChecked(False) vbox.addWidget(passphrase_msg) vbox.addWidget(passphrase_warning) vbox.addWidget(cb_phrase) wizard.exec_layout(vbox, next_enabled=next_enabled) if method in [TIM_NEW, TIM_RECOVER]: item = bg.checkedId() pin = cb_pin.isChecked() else: item = ' '.join(str(clean_text(text)).split()) pin = str(pin.text()) return (item, name.text(), pin, cb_phrase.isChecked())
def __init__(self, window, plugin, keystore, device_id): title = _("{} Settings").format(plugin.device) super(SettingsDialog, self).__init__(window, title) self.setMaximumWidth(540) devmgr = plugin.device_manager() config = devmgr.config handler = keystore.handler thread = keystore.thread hs_cols, hs_rows = (128, 64) def invoke_client(method, *args, **kw_args): unpair_after = kw_args.pop('unpair_after', False) def task(): client = devmgr.client_by_id(device_id) if not client: raise RuntimeError("Device not connected") if method: getattr(client, method)(*args, **kw_args) if unpair_after: devmgr.unpair_id(device_id) return client.features thread.add(task, on_success=update) def update(features): self.features = features set_label_enabled() if features.bootloader_hash: bl_hash = bh2u(features.bootloader_hash) bl_hash = "\n".join([bl_hash[:32], bl_hash[32:]]) else: bl_hash = "N/A" noyes = [_("No"), _("Yes")] endis = [_("Enable Passphrases"), _("Disable Passphrases")] disen = [_("Disabled"), _("Enabled")] setchange = [_("Set a PIN"), _("Change PIN")] version = "%d.%d.%d" % (features.major_version, features.minor_version, features.patch_version) device_label.setText(features.label) pin_set_label.setText(noyes[features.pin_protection]) passphrases_label.setText(disen[features.passphrase_protection]) bl_hash_label.setText(bl_hash) label_edit.setText(features.label) device_id_label.setText(features.device_id) initialized_label.setText(noyes[features.initialized]) version_label.setText(version) clear_pin_button.setVisible(features.pin_protection) clear_pin_warning.setVisible(features.pin_protection) pin_button.setText(setchange[features.pin_protection]) pin_msg.setVisible(not features.pin_protection) passphrase_button.setText(endis[features.passphrase_protection]) language_label.setText(features.language) def set_label_enabled(): label_apply.setEnabled(label_edit.text() != self.features.label) def rename(): invoke_client('change_label', label_edit.text()) def toggle_passphrase(): title = _("Confirm Toggle Passphrase Protection") currently_enabled = self.features.passphrase_protection if currently_enabled: msg = _("After disabling passphrases, you can only pair this " "Firo Electrum wallet if it had an empty passphrase. " "If its passphrase was not empty, you will need to " "create a new wallet with the install wizard. You " "can use this wallet again at any time by re-enabling " "passphrases and entering its passphrase.") else: msg = _("Your current Firo Electrum wallet can only be used with " "an empty passphrase. You must create a separate " "wallet with the install wizard for other passphrases " "as each one generates a new set of addresses.") msg += "\n\n" + _("Are you sure you want to proceed?") if not self.question(msg, title=title): return invoke_client('toggle_passphrase', unpair_after=currently_enabled) def change_homescreen(): filename = getOpenFileName( parent=self, title=_("Choose Homescreen"), config=config, ) if not filename: return # user cancelled if filename.endswith('.toif'): img = open(filename, 'rb').read() if img[:8] != b'TOIf\x90\x00\x90\x00': handler.show_error('File is not a TOIF file with size of 144x144') return else: from PIL import Image # FIXME im = Image.open(filename) if im.size != (128, 64): handler.show_error('Image must be 128 x 64 pixels') return im = im.convert('1') pix = im.load() img = bytearray(1024) for j in range(64): for i in range(128): if pix[i, j]: o = (i + j * 128) img[o // 8] |= (1 << (7 - o % 8)) img = bytes(img) invoke_client('change_homescreen', img) def clear_homescreen(): invoke_client('change_homescreen', b'\x00') def set_pin(): invoke_client('set_pin', remove=False) def clear_pin(): invoke_client('set_pin', remove=True) def wipe_device(): wallet = window.wallet if wallet and sum(wallet.get_balance()): title = _("Confirm Device Wipe") msg = _("Are you SURE you want to wipe the device?\n" "Your wallet still has Dash coins in it!") if not self.question(msg, title=title, icon=QMessageBox.Critical): return invoke_client('wipe_device', unpair_after=True) def slider_moved(): mins = timeout_slider.sliderPosition() timeout_minutes.setText(_("{:2d} minutes").format(mins)) def slider_released(): config.set_session_timeout(timeout_slider.sliderPosition() * 60) # Information tab info_tab = QWidget() info_layout = QVBoxLayout(info_tab) info_glayout = QGridLayout() info_glayout.setColumnStretch(2, 1) device_label = QLabel() pin_set_label = QLabel() passphrases_label = QLabel() version_label = QLabel() device_id_label = QLabel() bl_hash_label = QLabel() bl_hash_label.setWordWrap(True) language_label = QLabel() initialized_label = QLabel() rows = [ (_("Device Label"), device_label), (_("PIN set"), pin_set_label), (_("Passphrases"), passphrases_label), (_("Firmware Version"), version_label), (_("Device ID"), device_id_label), (_("Bootloader Hash"), bl_hash_label), (_("Language"), language_label), (_("Initialized"), initialized_label), ] for row_num, (label, widget) in enumerate(rows): info_glayout.addWidget(QLabel(label), row_num, 0) info_glayout.addWidget(widget, row_num, 1) info_layout.addLayout(info_glayout) # Settings tab settings_tab = QWidget() settings_layout = QVBoxLayout(settings_tab) settings_glayout = QGridLayout() # Settings tab - Label label_msg = QLabel(_("Name this {}. If you have multiple devices " "their labels help distinguish them.") .format(plugin.device)) label_msg.setWordWrap(True) label_label = QLabel(_("Device Label")) label_edit = QLineEdit() label_edit.setMinimumWidth(150) label_edit.setMaxLength(plugin.MAX_LABEL_LEN) label_apply = QPushButton(_("Apply")) label_apply.clicked.connect(rename) label_edit.textChanged.connect(set_label_enabled) settings_glayout.addWidget(label_label, 0, 0) settings_glayout.addWidget(label_edit, 0, 1, 1, 2) settings_glayout.addWidget(label_apply, 0, 3) settings_glayout.addWidget(label_msg, 1, 1, 1, -1) # Settings tab - PIN pin_label = QLabel(_("PIN Protection")) pin_button = QPushButton() pin_button.clicked.connect(set_pin) settings_glayout.addWidget(pin_label, 2, 0) settings_glayout.addWidget(pin_button, 2, 1) pin_msg = QLabel(_("PIN protection is strongly recommended. " "A PIN is your only protection against someone " "stealing your Dash coins if they obtain physical " "access to your {}.").format(plugin.device)) pin_msg.setWordWrap(True) pin_msg.setStyleSheet("color: red") settings_glayout.addWidget(pin_msg, 3, 1, 1, -1) # Settings tab - Homescreen homescreen_label = QLabel(_("Homescreen")) homescreen_change_button = QPushButton(_("Change...")) homescreen_clear_button = QPushButton(_("Reset")) homescreen_change_button.clicked.connect(change_homescreen) try: import PIL except ImportError: homescreen_change_button.setDisabled(True) homescreen_change_button.setToolTip( _("Required package 'PIL' is not available - Please install it.") ) homescreen_clear_button.clicked.connect(clear_homescreen) homescreen_msg = QLabel(_("You can set the homescreen on your " "device to personalize it. You must " "choose a {} x {} monochrome black and " "white image.").format(hs_cols, hs_rows)) homescreen_msg.setWordWrap(True) settings_glayout.addWidget(homescreen_label, 4, 0) settings_glayout.addWidget(homescreen_change_button, 4, 1) settings_glayout.addWidget(homescreen_clear_button, 4, 2) settings_glayout.addWidget(homescreen_msg, 5, 1, 1, -1) # Settings tab - Session Timeout timeout_label = QLabel(_("Session Timeout")) timeout_minutes = QLabel() timeout_slider = QSlider(Qt.Horizontal) timeout_slider.setRange(1, 60) timeout_slider.setSingleStep(1) timeout_slider.setTickInterval(5) timeout_slider.setTickPosition(QSlider.TicksBelow) timeout_slider.setTracking(True) timeout_msg = QLabel( _("Clear the session after the specified period " "of inactivity. Once a session has timed out, " "your PIN and passphrase (if enabled) must be " "re-entered to use the device.")) timeout_msg.setWordWrap(True) timeout_slider.setSliderPosition(config.get_session_timeout() // 60) slider_moved() timeout_slider.valueChanged.connect(slider_moved) timeout_slider.sliderReleased.connect(slider_released) settings_glayout.addWidget(timeout_label, 6, 0) settings_glayout.addWidget(timeout_slider, 6, 1, 1, 3) settings_glayout.addWidget(timeout_minutes, 6, 4) settings_glayout.addWidget(timeout_msg, 7, 1, 1, -1) settings_layout.addLayout(settings_glayout) settings_layout.addStretch(1) # Advanced tab advanced_tab = QWidget() advanced_layout = QVBoxLayout(advanced_tab) advanced_glayout = QGridLayout() # Advanced tab - clear PIN clear_pin_button = QPushButton(_("Disable PIN")) clear_pin_button.clicked.connect(clear_pin) clear_pin_warning = QLabel( _("If you disable your PIN, anyone with physical access to your " "{} device can spend your Dash coins.").format(plugin.device)) clear_pin_warning.setWordWrap(True) clear_pin_warning.setStyleSheet("color: red") advanced_glayout.addWidget(clear_pin_button, 0, 2) advanced_glayout.addWidget(clear_pin_warning, 1, 0, 1, 5) # Advanced tab - toggle passphrase protection passphrase_button = QPushButton() passphrase_button.clicked.connect(toggle_passphrase) passphrase_msg = WWLabel(PASSPHRASE_HELP) passphrase_warning = WWLabel(PASSPHRASE_NOT_PIN) passphrase_warning.setStyleSheet("color: red") advanced_glayout.addWidget(passphrase_button, 3, 2) advanced_glayout.addWidget(passphrase_msg, 4, 0, 1, 5) advanced_glayout.addWidget(passphrase_warning, 5, 0, 1, 5) # Advanced tab - wipe device wipe_device_button = QPushButton(_("Wipe Device")) wipe_device_button.clicked.connect(wipe_device) wipe_device_msg = QLabel( _("Wipe the device, removing all data from it. The firmware " "is left unchanged.")) wipe_device_msg.setWordWrap(True) wipe_device_warning = QLabel( _("Only wipe a device if you have the recovery seed written down " "and the device wallet(s) are empty, otherwise the Dash coins " "will be lost forever.")) wipe_device_warning.setWordWrap(True) wipe_device_warning.setStyleSheet("color: red") advanced_glayout.addWidget(wipe_device_button, 6, 2) advanced_glayout.addWidget(wipe_device_msg, 7, 0, 1, 5) advanced_glayout.addWidget(wipe_device_warning, 8, 0, 1, 5) advanced_layout.addLayout(advanced_glayout) advanced_layout.addStretch(1) tabs = QTabWidget(self) tabs.addTab(info_tab, _("Information")) tabs.addTab(settings_tab, _("Settings")) tabs.addTab(advanced_tab, _("Advanced")) dialog_vbox = QVBoxLayout(self) dialog_vbox.addWidget(tabs) dialog_vbox.addLayout(Buttons(CloseButton(self))) # Update information invoke_client(None)
def request_trezor_init_settings(self, wizard, method, device_id): vbox = QVBoxLayout() next_enabled = True devmgr = self.device_manager() client = devmgr.client_by_id(device_id) if not client: raise Exception(_("The device was disconnected.")) model = client.get_trezor_model() fw_version = client.client.version capabilities = client.client.features.capabilities have_shamir = Capability.Shamir in capabilities # label label = QLabel(_("Enter a label to name your device:")) name = QLineEdit() hl = QHBoxLayout() hl.addWidget(label) hl.addWidget(name) hl.addStretch(1) vbox.addLayout(hl) # Backup type gb_backuptype = QGroupBox() hbox_backuptype = QHBoxLayout() gb_backuptype.setLayout(hbox_backuptype) vbox.addWidget(gb_backuptype) gb_backuptype.setTitle(_('Select backup type:')) bg_backuptype = QButtonGroup() rb_single = QRadioButton(gb_backuptype) rb_single.setText(_('Single seed (BIP39)')) bg_backuptype.addButton(rb_single) bg_backuptype.setId(rb_single, BackupType.Bip39) hbox_backuptype.addWidget(rb_single) rb_single.setChecked(True) rb_shamir = QRadioButton(gb_backuptype) rb_shamir.setText(_('Shamir')) bg_backuptype.addButton(rb_shamir) bg_backuptype.setId(rb_shamir, BackupType.Slip39_Basic) hbox_backuptype.addWidget(rb_shamir) rb_shamir.setEnabled(Capability.Shamir in capabilities) rb_shamir.setVisible(False) # visible with "expert settings" rb_shamir_groups = QRadioButton(gb_backuptype) rb_shamir_groups.setText(_('Super Shamir')) bg_backuptype.addButton(rb_shamir_groups) bg_backuptype.setId(rb_shamir_groups, BackupType.Slip39_Advanced) hbox_backuptype.addWidget(rb_shamir_groups) rb_shamir_groups.setEnabled(Capability.ShamirGroups in capabilities) rb_shamir_groups.setVisible(False) # visible with "expert settings" # word count word_count_buttons = {} gb_numwords = QGroupBox() hbox1 = QHBoxLayout() gb_numwords.setLayout(hbox1) vbox.addWidget(gb_numwords) gb_numwords.setTitle(_("Select seed/share length:")) bg_numwords = QButtonGroup() for count in (12, 18, 20, 24, 33): rb = QRadioButton(gb_numwords) word_count_buttons[count] = rb rb.setText(_("{:d} words").format(count)) bg_numwords.addButton(rb) bg_numwords.setId(rb, count) hbox1.addWidget(rb) rb.setChecked(True) def configure_word_counts(): if model == "1": checked_wordcount = 24 else: checked_wordcount = 12 if method == TIM_RECOVER: if have_shamir: valid_word_counts = (12, 18, 20, 24, 33) else: valid_word_counts = (12, 18, 24) elif rb_single.isChecked(): valid_word_counts = (12, 18, 24) gb_numwords.setTitle(_('Select seed length:')) else: valid_word_counts = (20, 33) checked_wordcount = 20 gb_numwords.setTitle(_('Select share length:')) word_count_buttons[checked_wordcount].setChecked(True) for c, btn in word_count_buttons.items(): btn.setVisible(c in valid_word_counts) bg_backuptype.buttonClicked.connect(configure_word_counts) configure_word_counts() # set up conditional visibility: # 1. backup_type is only visible when creating new seed gb_backuptype.setVisible(method == TIM_NEW) # 2. word_count is not visible when recovering on TT if method == TIM_RECOVER and model != "1": gb_numwords.setVisible(False) # PIN cb_pin = QCheckBox(_('Enable PIN protection')) cb_pin.setChecked(True) vbox.addWidget(WWLabel(RECOMMEND_PIN)) vbox.addWidget(cb_pin) # "expert settings" button expert_vbox = QVBoxLayout() expert_widget = QWidget() expert_widget.setLayout(expert_vbox) expert_widget.setVisible(False) expert_button = QPushButton(_("Show expert settings")) def show_expert_settings(): expert_button.setVisible(False) expert_widget.setVisible(True) rb_shamir.setVisible(True) rb_shamir_groups.setVisible(True) expert_button.clicked.connect(show_expert_settings) vbox.addWidget(expert_button) # passphrase passphrase_msg = WWLabel(PASSPHRASE_HELP_SHORT) passphrase_warning = WWLabel(PASSPHRASE_NOT_PIN) passphrase_warning.setStyleSheet("color: red") cb_phrase = QCheckBox(_('Enable passphrases')) cb_phrase.setChecked(False) expert_vbox.addWidget(passphrase_msg) expert_vbox.addWidget(passphrase_warning) expert_vbox.addWidget(cb_phrase) # ask for recovery type (random word order OR matrix) bg_rectype = None if method == TIM_RECOVER and model == '1': gb_rectype = QGroupBox() hbox_rectype = QHBoxLayout() gb_rectype.setLayout(hbox_rectype) expert_vbox.addWidget(gb_rectype) gb_rectype.setTitle(_("Select recovery type:")) bg_rectype = QButtonGroup() rb1 = QRadioButton(gb_rectype) rb1.setText(_('Scrambled words')) bg_rectype.addButton(rb1) bg_rectype.setId(rb1, RecoveryDeviceType.ScrambledWords) hbox_rectype.addWidget(rb1) rb1.setChecked(True) rb2 = QRadioButton(gb_rectype) rb2.setText(_('Matrix')) bg_rectype.addButton(rb2) bg_rectype.setId(rb2, RecoveryDeviceType.Matrix) hbox_rectype.addWidget(rb2) # no backup cb_no_backup = None if method == TIM_NEW: cb_no_backup = QCheckBox(f'''{_('Enable seedless mode')}''') cb_no_backup.setChecked(False) if (model == '1' and fw_version >= (1, 7, 1) or model == 'T' and fw_version >= (2, 0, 9)): cb_no_backup.setToolTip(SEEDLESS_MODE_WARNING) else: cb_no_backup.setEnabled(False) cb_no_backup.setToolTip(_('Firmware version too old.')) expert_vbox.addWidget(cb_no_backup) vbox.addWidget(expert_widget) wizard.exec_layout(vbox, next_enabled=next_enabled) return TrezorInitSettings( word_count=bg_numwords.checkedId(), label=name.text(), pin_enabled=cb_pin.isChecked(), passphrase_enabled=cb_phrase.isChecked(), recovery_type=bg_rectype.checkedId() if bg_rectype else None, backup_type=bg_backuptype.checkedId(), no_backup=cb_no_backup.isChecked() if cb_no_backup else False, )
class Plugin(RevealerPlugin): MAX_PLAINTEXT_LEN = 189 # chars def __init__(self, parent, config, name): RevealerPlugin.__init__(self, parent, config, name) self.base_dir = os.path.join(config.electrum_path(), 'revealer') if self.config.get('calibration_h') is None: self.config.set_key('calibration_h', 0) if self.config.get('calibration_v') is None: self.config.set_key('calibration_v', 0) self.calibration_h = self.config.get('calibration_h') self.calibration_v = self.config.get('calibration_v') self.f_size = QSize(1014*2, 642*2) self.abstand_h = 21 self.abstand_v = 34 self.calibration_noise = int('10' * 128) self.rawnoise = False make_dir(self.base_dir) self.extension = False @hook def create_status_bar(self, parent): b = StatusBarButton(read_QIcon('revealer.png'), "Revealer "+_("Visual Cryptography Plugin"), partial(self.setup_dialog, parent)) parent.addPermanentWidget(b) def requires_settings(self): return True def settings_widget(self, window): return EnterButton(_('Printer Calibration'), partial(self.calibration_dialog, window)) def password_dialog(self, msg=None, parent=None): from electrum_firo.gui.qt.password_dialog import PasswordDialog parent = parent or self d = PasswordDialog(parent, msg) return d.run() def get_seed(self): password = None if self.wallet.has_keystore_encryption(): password = self.password_dialog(parent=self.d.parent()) if not password: raise UserCancelled() keystore = self.wallet.get_keystore() if not keystore or not keystore.has_seed(): return self.extension = bool(keystore.get_passphrase(password)) return keystore.get_seed(password) def setup_dialog(self, window): self.wallet = window.parent().wallet self.update_wallet_name(self.wallet) self.user_input = False self.d = WindowModalDialog(window, "Setup Dialog") self.d.setMinimumWidth(500) self.d.setMinimumHeight(210) self.d.setMaximumHeight(320) self.d.setContentsMargins(11,11,1,1) self.hbox = QHBoxLayout(self.d) vbox = QVBoxLayout() logo = QLabel() self.hbox.addWidget(logo) logo.setPixmap(QPixmap(icon_path('revealer.png'))) logo.setAlignment(Qt.AlignLeft) self.hbox.addSpacing(16) vbox.addWidget(WWLabel("<b>"+_("Revealer Visual Cryptography Plugin")+"</b><br><br>" +_("To encrypt a secret, first create or load noise.")+"<br/>")) vbox.addSpacing(7) bcreate = QPushButton(_("Create a new Revealer")) bcreate.setMaximumWidth(181) bcreate.setDefault(True) vbox.addWidget(bcreate, Qt.AlignCenter) self.load_noise = ScanQRTextEdit(config=self.config) self.load_noise.setTabChangesFocus(True) self.load_noise.textChanged.connect(self.on_edit) self.load_noise.setMaximumHeight(33) self.hbox.addLayout(vbox) vbox.addWidget(WWLabel(_("or type an existing revealer code below and click 'next':"))) vbox.addWidget(self.load_noise) vbox.addSpacing(3) self.next_button = QPushButton(_("Next"), self.d) self.next_button.setEnabled(False) vbox.addLayout(Buttons(self.next_button)) self.next_button.clicked.connect(self.d.close) self.next_button.clicked.connect(partial(self.cypherseed_dialog, window)) def mk_digital(): try: self.make_digital(self.d) except Exception: self.logger.exception('') else: self.cypherseed_dialog(window) bcreate.clicked.connect(mk_digital) return bool(self.d.exec_()) def get_noise(self): text = self.load_noise.text() return ''.join(text.split()).lower() def on_edit(self): txt = self.get_noise() versioned_seed = self.get_versioned_seed_from_user_input(txt) if versioned_seed: self.versioned_seed = versioned_seed self.user_input = bool(versioned_seed) self.next_button.setEnabled(bool(versioned_seed)) def make_digital(self, dialog): self.make_rawnoise(True) self.bdone(dialog) self.d.close() def get_path_to_revealer_file(self, ext: str= '') -> str: version = self.versioned_seed.version code_id = self.versioned_seed.checksum filename = self.filename_prefix + version + "_" + code_id + ext path = os.path.join(self.base_dir, filename) return os.path.normcase(os.path.abspath(path)) def get_path_to_calibration_file(self): path = os.path.join(self.base_dir, 'calibration.pdf') return os.path.normcase(os.path.abspath(path)) def bcrypt(self, dialog): self.rawnoise = False version = self.versioned_seed.version code_id = self.versioned_seed.checksum dialog.show_message(''.join([_("{} encrypted for Revealer {}_{} saved as PNG and PDF at: ").format(self.was, version, code_id), "<b>", self.get_path_to_revealer_file(), "</b>", "<br/>", "<br/>", "<b>", _("Always check your backups.")]), rich_text=True) dialog.close() def ext_warning(self, dialog): dialog.show_message(''.join(["<b>",_("Warning"), ": </b>", _("your seed extension will <b>not</b> be included in the encrypted backup.")]), rich_text=True) dialog.close() def bdone(self, dialog): version = self.versioned_seed.version code_id = self.versioned_seed.checksum dialog.show_message(''.join([_("Digital Revealer ({}_{}) saved as PNG and PDF at:").format(version, code_id), "<br/>","<b>", self.get_path_to_revealer_file(), '</b>']), rich_text=True) def customtxt_limits(self): txt = self.text.text() self.max_chars.setVisible(False) self.char_count.setText(f"({len(txt)}/{self.MAX_PLAINTEXT_LEN})") if len(txt)>0: self.ctext.setEnabled(True) if len(txt) > self.MAX_PLAINTEXT_LEN: self.text.setPlainText(txt[:self.MAX_PLAINTEXT_LEN]) self.max_chars.setVisible(True) def t(self): self.txt = self.text.text() self.seed_img(is_seed=False) def warn_old_revealer(self): if self.versioned_seed.version == '0': link = "https://revealer.cc/revealer-warning-and-upgrade/" self.d.show_warning(("<b>{warning}: </b>{ver0}<br>" "{url}<br>" "{risk}") .format(warning=_("Warning"), ver0=_("Revealers starting with 0 are not secure due to a vulnerability."), url=_("More info at: {}").format(f'<a href="{link}">{link}</a>'), risk=_("Proceed at your own risk.")), rich_text=True) def cypherseed_dialog(self, window): self.warn_old_revealer() d = WindowModalDialog(window, "Encryption Dialog") d.setMinimumWidth(500) d.setMinimumHeight(210) d.setMaximumHeight(450) d.setContentsMargins(11, 11, 1, 1) self.c_dialog = d hbox = QHBoxLayout(d) self.vbox = QVBoxLayout() logo = QLabel() hbox.addWidget(logo) logo.setPixmap(QPixmap(icon_path('revealer.png'))) logo.setAlignment(Qt.AlignLeft) hbox.addSpacing(16) self.vbox.addWidget(WWLabel("<b>" + _("Revealer Visual Cryptography Plugin") + "</b><br><br>" + _("Ready to encrypt for revealer {}") .format(self.versioned_seed.version+'_'+self.versioned_seed.checksum))) self.vbox.addSpacing(11) hbox.addLayout(self.vbox) grid = QGridLayout() self.vbox.addLayout(grid) cprint = QPushButton(_("Encrypt {}'s seed").format(self.wallet_name)) cprint.setMaximumWidth(250) cprint.clicked.connect(partial(self.seed_img, True)) self.vbox.addWidget(cprint) self.vbox.addSpacing(1) self.vbox.addWidget(WWLabel("<b>"+_("OR")+"</b> "+_("type a custom alphanumerical secret below:"))) self.text = ScanQRTextEdit(config=self.config) self.text.setTabChangesFocus(True) self.text.setMaximumHeight(70) self.text.textChanged.connect(self.customtxt_limits) self.vbox.addWidget(self.text) self.char_count = WWLabel("") self.char_count.setAlignment(Qt.AlignRight) self.vbox.addWidget(self.char_count) self.max_chars = WWLabel("<font color='red'>" + _("This version supports a maximum of {} characters.").format(self.MAX_PLAINTEXT_LEN) +"</font>") self.vbox.addWidget(self.max_chars) self.max_chars.setVisible(False) self.ctext = QPushButton(_("Encrypt custom secret")) self.ctext.clicked.connect(self.t) self.vbox.addWidget(self.ctext) self.ctext.setEnabled(False) self.vbox.addSpacing(11) self.vbox.addLayout(Buttons(CloseButton(d))) self.vbox.addWidget( QLabel("<br>"+"<b>" + _("Warning ") + "</b>: " + _("each Revealer is a one-time-pad, use it for a single secret."))) return bool(d.exec_()) def update_wallet_name(self, name): self.wallet_name = str(name) def seed_img(self, is_seed = True): if is_seed: try: cseed = self.get_seed() except UserCancelled: return except InvalidPassword as e: self.d.show_error(str(e)) return if not cseed: self.d.show_message(_("This wallet has no seed")) return txt = cseed.upper() else: txt = self.txt.upper() img = QImage(self.SIZE[0], self.SIZE[1], QImage.Format_Mono) bitmap = QBitmap.fromImage(img, Qt.MonoOnly) bitmap.fill(Qt.white) painter = QPainter() painter.begin(bitmap) QFontDatabase.addApplicationFont(os.path.join(os.path.dirname(__file__), 'SourceSansPro-Bold.otf')) if len(txt) < 102 : fontsize = 15 linespace = 15 max_letters = 17 max_lines = 6 max_words = 3 else: fontsize = 12 linespace = 10 max_letters = 21 max_lines = 9 max_words = int(max_letters/4) font = QFont('Source Sans Pro', fontsize, QFont.Bold) font.setLetterSpacing(QFont.PercentageSpacing, 100) font.setPixelSize(fontsize) painter.setFont(font) seed_array = txt.split(' ') for n in range(max_lines): nwords = max_words temp_seed = seed_array[:nwords] while len(' '.join(map(str, temp_seed))) > max_letters: nwords = nwords - 1 temp_seed = seed_array[:nwords] painter.drawText(QRect(0, linespace*n, self.SIZE[0], self.SIZE[1]), Qt.AlignHCenter, ' '.join(map(str, temp_seed))) del seed_array[:nwords] painter.end() img = bitmap.toImage() if (self.rawnoise == False): self.make_rawnoise() self.make_cypherseed(img, self.rawnoise, False, is_seed) return img def make_rawnoise(self, create_revealer=False): if not self.user_input: self.versioned_seed = self.gen_random_versioned_seed() assert self.versioned_seed w, h = self.SIZE rawnoise = QImage(w, h, QImage.Format_Mono) noise_map = self.get_noise_map(self.versioned_seed) for (x,y), pixel in noise_map.items(): rawnoise.setPixel(x, y, pixel) self.rawnoise = rawnoise if create_revealer: self.make_revealer() def make_calnoise(self): random.seed(self.calibration_noise) w, h = self.SIZE rawnoise = QImage(w, h, QImage.Format_Mono) for x in range(w): for y in range(h): rawnoise.setPixel(x,y,random.randint(0, 1)) self.calnoise = self.pixelcode_2x2(rawnoise) def make_revealer(self): revealer = self.pixelcode_2x2(self.rawnoise) revealer.invertPixels() revealer = QBitmap.fromImage(revealer) revealer = revealer.scaled(self.f_size, Qt.KeepAspectRatio) revealer = self.overlay_marks(revealer) self.filename_prefix = 'revealer_' revealer.save(self.get_path_to_revealer_file('.png')) self.toPdf(QImage(revealer)) def make_cypherseed(self, img, rawnoise, calibration=False, is_seed = True): img = img.convertToFormat(QImage.Format_Mono) p = QPainter() p.begin(img) p.setCompositionMode(26) #xor p.drawImage(0, 0, rawnoise) p.end() cypherseed = self.pixelcode_2x2(img) cypherseed = QBitmap.fromImage(cypherseed) cypherseed = cypherseed.scaled(self.f_size, Qt.KeepAspectRatio) cypherseed = self.overlay_marks(cypherseed, True, calibration) if not is_seed: self.filename_prefix = 'custom_secret_' self.was = _('Custom secret') else: self.filename_prefix = self.wallet_name + '_seed_' self.was = self.wallet_name + ' ' + _('seed') if self.extension: self.ext_warning(self.c_dialog) if not calibration: self.toPdf(QImage(cypherseed)) cypherseed.save(self.get_path_to_revealer_file('.png')) self.bcrypt(self.c_dialog) return cypherseed def calibration(self): img = QImage(self.SIZE[0], self.SIZE[1], QImage.Format_Mono) bitmap = QBitmap.fromImage(img, Qt.MonoOnly) bitmap.fill(Qt.black) self.make_calnoise() img = self.overlay_marks(self.calnoise.scaledToHeight(self.f_size.height()), False, True) self.calibration_pdf(img) QDesktopServices.openUrl(QUrl.fromLocalFile(self.get_path_to_calibration_file())) return img def toPdf(self, image): printer = QPrinter() printer.setPaperSize(QSizeF(210, 297), QPrinter.Millimeter) printer.setResolution(600) printer.setOutputFormat(QPrinter.PdfFormat) printer.setOutputFileName(self.get_path_to_revealer_file('.pdf')) printer.setPageMargins(0,0,0,0,6) painter = QPainter() painter.begin(printer) delta_h = round(image.width()/self.abstand_v) delta_v = round(image.height()/self.abstand_h) size_h = 2028+((int(self.calibration_h)*2028/(2028-(delta_h*2)+int(self.calibration_h)))/2) size_v = 1284+((int(self.calibration_v)*1284/(1284-(delta_v*2)+int(self.calibration_v)))/2) image = image.scaled(size_h, size_v) painter.drawImage(553,533, image) wpath = QPainterPath() wpath.addRoundedRect(QRectF(553,533, size_h, size_v), 19, 19) painter.setPen(QPen(Qt.black, 1)) painter.drawPath(wpath) painter.end() def calibration_pdf(self, image): printer = QPrinter() printer.setPaperSize(QSizeF(210, 297), QPrinter.Millimeter) printer.setResolution(600) printer.setOutputFormat(QPrinter.PdfFormat) printer.setOutputFileName(self.get_path_to_calibration_file()) printer.setPageMargins(0,0,0,0,6) painter = QPainter() painter.begin(printer) painter.drawImage(553,533, image) font = QFont('Source Sans Pro', 10, QFont.Bold) painter.setFont(font) painter.drawText(254,277, _("Calibration sheet")) font = QFont('Source Sans Pro', 7, QFont.Bold) painter.setFont(font) painter.drawText(600,2077, _("Instructions:")) font = QFont('Source Sans Pro', 7, QFont.Normal) painter.setFont(font) painter.drawText(700, 2177, _("1. Place this paper on a flat and well iluminated surface.")) painter.drawText(700, 2277, _("2. Align your Revealer borderlines to the dashed lines on the top and left.")) painter.drawText(700, 2377, _("3. Press slightly the Revealer against the paper and read the numbers that best " "match on the opposite sides. ")) painter.drawText(700, 2477, _("4. Type the numbers in the software")) painter.end() def pixelcode_2x2(self, img): result = QImage(img.width()*2, img.height()*2, QImage.Format_ARGB32) white = qRgba(255,255,255,0) black = qRgba(0,0,0,255) for x in range(img.width()): for y in range(img.height()): c = img.pixel(QPoint(x,y)) colors = QColor(c).getRgbF() if colors[0]: result.setPixel(x*2+1,y*2+1, black) result.setPixel(x*2,y*2+1, white) result.setPixel(x*2+1,y*2, white) result.setPixel(x*2, y*2, black) else: result.setPixel(x*2+1,y*2+1, white) result.setPixel(x*2,y*2+1, black) result.setPixel(x*2+1,y*2, black) result.setPixel(x*2, y*2, white) return result def overlay_marks(self, img, is_cseed=False, calibration_sheet=False): border_color = Qt.white base_img = QImage(self.f_size.width(),self.f_size.height(), QImage.Format_ARGB32) base_img.fill(border_color) img = QImage(img) painter = QPainter() painter.begin(base_img) total_distance_h = round(base_img.width() / self.abstand_v) dist_v = round(total_distance_h) / 2 dist_h = round(total_distance_h) / 2 img = img.scaledToWidth(base_img.width() - (2 * (total_distance_h))) painter.drawImage(total_distance_h, total_distance_h, img) #frame around image pen = QPen(Qt.black, 2) painter.setPen(pen) #horz painter.drawLine(0, total_distance_h, base_img.width(), total_distance_h) painter.drawLine(0, base_img.height()-(total_distance_h), base_img.width(), base_img.height()-(total_distance_h)) #vert painter.drawLine(total_distance_h, 0, total_distance_h, base_img.height()) painter.drawLine(base_img.width()-(total_distance_h), 0, base_img.width()-(total_distance_h), base_img.height()) #border around img border_thick = 6 Rpath = QPainterPath() Rpath.addRect(QRectF((total_distance_h)+(border_thick/2), (total_distance_h)+(border_thick/2), base_img.width()-((total_distance_h)*2)-((border_thick)-1), (base_img.height()-((total_distance_h))*2)-((border_thick)-1))) pen = QPen(Qt.black, border_thick) pen.setJoinStyle (Qt.MiterJoin) painter.setPen(pen) painter.drawPath(Rpath) Bpath = QPainterPath() Bpath.addRect(QRectF((total_distance_h), (total_distance_h), base_img.width()-((total_distance_h)*2), (base_img.height()-((total_distance_h))*2))) pen = QPen(Qt.black, 1) painter.setPen(pen) painter.drawPath(Bpath) pen = QPen(Qt.black, 1) painter.setPen(pen) painter.drawLine(0, base_img.height()/2, total_distance_h, base_img.height()/2) painter.drawLine(base_img.width()/2, 0, base_img.width()/2, total_distance_h) painter.drawLine(base_img.width()-total_distance_h, base_img.height()/2, base_img.width(), base_img.height()/2) painter.drawLine(base_img.width()/2, base_img.height(), base_img.width()/2, base_img.height() - total_distance_h) #print code f_size = 37 QFontDatabase.addApplicationFont(os.path.join(os.path.dirname(__file__), 'DejaVuSansMono-Bold.ttf')) font = QFont("DejaVu Sans Mono", f_size-11, QFont.Bold) font.setPixelSize(35) painter.setFont(font) if not calibration_sheet: if is_cseed: #its a secret painter.setPen(QPen(Qt.black, 1, Qt.DashDotDotLine)) painter.drawLine(0, dist_v, base_img.width(), dist_v) 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()) painter.drawImage(((total_distance_h))+11, ((total_distance_h))+11, QImage(icon_path('electrumb.png')).scaledToWidth(2.1*(total_distance_h), Qt.SmoothTransformation)) painter.setPen(QPen(Qt.white, border_thick*8)) painter.drawLine(base_img.width()-((total_distance_h))-(border_thick*8)/2-(border_thick/2)-2, (base_img.height()-((total_distance_h)))-((border_thick*8)/2)-(border_thick/2)-2, base_img.width()-((total_distance_h))-(border_thick*8)/2-(border_thick/2)-2 - 77, (base_img.height()-((total_distance_h)))-((border_thick*8)/2)-(border_thick/2)-2) painter.setPen(QColor(0,0,0,255)) painter.drawText(QRect(0, base_img.height()-107, base_img.width()-total_distance_h - border_thick - 11, base_img.height()-total_distance_h - border_thick), Qt.AlignRight, self.versioned_seed.version + '_'+self.versioned_seed.checksum) painter.end() else: # revealer painter.setPen(QPen(border_color, 17)) painter.drawLine(0, dist_v, base_img.width(), dist_v) 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()) painter.setPen(QPen(Qt.black, 2)) painter.drawLine(0, dist_v, base_img.width(), dist_v) 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(1.3*(total_distance_h)) painter.drawImage((total_distance_h)+ (border_thick), ((total_distance_h))+ (border_thick), logo, Qt.SmoothTransformation) #frame around logo painter.setPen(QPen(Qt.black, border_thick)) painter.drawLine(total_distance_h+border_thick, total_distance_h+logo.height()+3*(border_thick/2), total_distance_h+logo.width()+border_thick, total_distance_h+logo.height()+3*(border_thick/2)) painter.drawLine(logo.width()+total_distance_h+3*(border_thick/2), total_distance_h+(border_thick), total_distance_h+logo.width()+3*(border_thick/2), total_distance_h+logo.height()+(border_thick)) #frame around code/qr qr_size = 179 painter.drawLine((base_img.width()-((total_distance_h))-(border_thick/2)-2)-qr_size, (base_img.height()-((total_distance_h)))-((border_thick*8))-(border_thick/2)-2, (base_img.width()/2+(total_distance_h/2)-border_thick-(border_thick*8)/2)-qr_size, (base_img.height()-((total_distance_h)))-((border_thick*8))-(border_thick/2)-2) painter.drawLine((base_img.width()/2+(total_distance_h/2)-border_thick-(border_thick*8)/2)-qr_size, (base_img.height()-((total_distance_h)))-((border_thick*8))-(border_thick/2)-2, base_img.width()/2 + (total_distance_h/2)-border_thick-(border_thick*8)/2-qr_size, ((base_img.height()-((total_distance_h)))-(border_thick/2)-2)) painter.setPen(QPen(Qt.white, border_thick * 8)) painter.drawLine( base_img.width() - ((total_distance_h)) - (border_thick * 8) / 2 - (border_thick / 2) - 2, (base_img.height() - ((total_distance_h))) - ((border_thick * 8) / 2) - (border_thick / 2) - 2, base_img.width() / 2 + (total_distance_h / 2) - border_thick - qr_size, (base_img.height() - ((total_distance_h))) - ((border_thick * 8) / 2) - (border_thick / 2) - 2) painter.setPen(QColor(0,0,0,255)) painter.drawText(QRect(((base_img.width()/2) +21)-qr_size, base_img.height()-107, base_img.width()-total_distance_h - border_thick -93, base_img.height()-total_distance_h - border_thick), Qt.AlignLeft, self.versioned_seed.get_ui_string_version_plus_seed()) painter.drawText(QRect(0, base_img.height()-107, base_img.width()-total_distance_h - border_thick -3 -qr_size, base_img.height()-total_distance_h - border_thick), Qt.AlignRight, self.versioned_seed.checksum) # draw qr code qr_qt = self.paintQR(self.versioned_seed.get_ui_string_version_plus_seed() + self.versioned_seed.checksum) target = QRectF(base_img.width()-65-qr_size, base_img.height()-65-qr_size, qr_size, qr_size) painter.drawImage(target, qr_qt) painter.setPen(QPen(Qt.black, 4)) painter.drawLine(base_img.width()-65-qr_size, base_img.height()-65-qr_size, base_img.width() - 65 - qr_size, (base_img.height() - ((total_distance_h))) - ((border_thick * 8)) - (border_thick / 2) - 4 ) painter.drawLine(base_img.width()-65-qr_size, base_img.height()-65-qr_size, base_img.width() - 65, base_img.height()-65-qr_size ) painter.end() else: # calibration only painter.end() cal_img = QImage(self.f_size.width() + 100, self.f_size.height() + 100, QImage.Format_ARGB32) cal_img.fill(Qt.white) cal_painter = QPainter() cal_painter.begin(cal_img) cal_painter.drawImage(0,0, base_img) #black lines in the middle of border top left only cal_painter.setPen(QPen(Qt.black, 1, Qt.DashDotDotLine)) cal_painter.drawLine(0, dist_v, base_img.width(), dist_v) cal_painter.drawLine(dist_h, 0, dist_h, base_img.height()) pen = QPen(Qt.black, 2, Qt.DashDotDotLine) cal_painter.setPen(pen) n=15 cal_painter.setFont(QFont("DejaVu Sans Mono", 21, QFont.Bold)) for x in range(-n,n): #lines on bottom (vertical calibration) cal_painter.drawLine((((base_img.width())/(n*2)) *(x))+ (base_img.width()/2)-13, x+2+base_img.height()-(dist_v), (((base_img.width())/(n*2)) *(x))+ (base_img.width()/2)+13, x+2+base_img.height()-(dist_v)) num_pos = 9 if x > 9 : num_pos = 17 if x < 0 : num_pos = 20 if x < -9: num_pos = 27 cal_painter.drawText((((base_img.width())/(n*2)) *(x))+ (base_img.width()/2)-num_pos, 50+base_img.height()-(dist_v), str(x)) #lines on the right (horizontal calibrations) cal_painter.drawLine(x+2+(base_img.width()-(dist_h)), ((base_img.height()/(2*n)) *(x))+ (base_img.height()/n)+(base_img.height()/2)-13, x+2+(base_img.width()-(dist_h)), ((base_img.height()/(2*n)) *(x))+ (base_img.height()/n)+(base_img.height()/2)+13) cal_painter.drawText(30+(base_img.width()-(dist_h)), ((base_img.height()/(2*n)) *(x))+ (base_img.height()/2)+13, str(x)) cal_painter.end() base_img = cal_img return base_img def paintQR(self, data): if not data: return qr = qrcode.QRCode() qr.add_data(data) matrix = qr.get_matrix() k = len(matrix) border_color = Qt.white base_img = QImage(k * 5, k * 5, QImage.Format_ARGB32) base_img.fill(border_color) qrpainter = QPainter() qrpainter.begin(base_img) boxsize = 5 size = k * boxsize left = (base_img.width() - size)/2 top = (base_img.height() - size)/2 qrpainter.setBrush(Qt.black) qrpainter.setPen(Qt.black) for r in range(k): for c in range(k): if matrix[r][c]: qrpainter.drawRect(left+c*boxsize, top+r*boxsize, boxsize - 1, boxsize - 1) qrpainter.end() return base_img def calibration_dialog(self, window): d = WindowModalDialog(window, _("Revealer - Printer calibration settings")) d.setMinimumSize(100, 200) vbox = QVBoxLayout(d) vbox.addWidget(QLabel(''.join(["<br/>", _("If you have an old printer, or want optimal precision"),"<br/>", _("print the calibration pdf and follow the instructions "), "<br/>","<br/>", ]))) self.calibration_h = self.config.get('calibration_h') self.calibration_v = self.config.get('calibration_v') cprint = QPushButton(_("Open calibration pdf")) cprint.clicked.connect(self.calibration) vbox.addWidget(cprint) vbox.addWidget(QLabel(_('Calibration values:'))) grid = QGridLayout() vbox.addLayout(grid) grid.addWidget(QLabel(_('Right side')), 0, 0) horizontal = QLineEdit() horizontal.setText(str(self.calibration_h)) grid.addWidget(horizontal, 0, 1) grid.addWidget(QLabel(_('Bottom')), 1, 0) vertical = QLineEdit() vertical.setText(str(self.calibration_v)) grid.addWidget(vertical, 1, 1) vbox.addStretch() vbox.addSpacing(13) vbox.addLayout(Buttons(CloseButton(d), OkButton(d))) if not d.exec_(): return self.calibration_h = int(Decimal(horizontal.text())) self.config.set_key('calibration_h', self.calibration_h) self.calibration_v = int(Decimal(vertical.text())) self.config.set_key('calibration_v', self.calibration_v)
def __init__(self, window, plugin): WindowModalDialog.__init__(self, window, plugin.MSG_TITLE) self.setMinimumSize(800, 400) self.wallet = w = window.parent().wallet self.plugin = plugin self.config = plugin.config self.network = Network.get_instance() coro = plugin.init_scans(w) fut = asyncio.run_coroutine_threadsafe(coro, self.network.asyncio_loop) fut.result() g = QGridLayout(self) g.addWidget(WWLabel(plugin.MSG_SCAN_TITLE), 0, 0, 1, -1) self.scan_list = ScanListWidget(self) self.scan_list.update() self.scan_list.itemChanged.connect(self.scan_list_item_changed) g.addWidget(self.scan_list, 1, 0, 1, -1) g.addWidget(QLabel(plugin.MSG_SCAN_COUNT), 2, 0) self.scan_cnt_sb = QSpinBox() self.scan_cnt_sb.setRange(plugin.MIN_SCAN_CNT, plugin.MAX_SCAN_CNT) self.scan_cnt_sb.setValue(plugin.DEF_SCAN_CNT) self.scan_cnt_sb.setSingleStep(plugin.DEF_SCAN_CNT) self.scan_cnt_sb.valueChanged.connect(self.on_scan_cnt_value_changed) g.addWidget(self.scan_cnt_sb, 2, 1) self.do_scan_btn = QPushButton() self.set_do_scan_btn_txt(plugin.DEF_SCAN_CNT) self.do_scan_btn.clicked.connect(partial(self.do_scan, w)) g.addWidget(self.do_scan_btn, 2, 3) g.addWidget(QLabel(plugin.MSG_PROGRESS), 2, 4) self.scan_progress_pb = QProgressBar() self.scan_progress_pb.setValue(0) g.addWidget(self.scan_progress_pb , 2, 5) g.setRowStretch(10, 1) hbox = QHBoxLayout() self.reset_scans_btn = QPushButton(plugin.MSG_RESET) self.reset_scans_btn.clicked.connect(partial(self.reset_scans, w)) hbox.addWidget(self.reset_scans_btn) hbox.addStretch(1) self.add_found_btn = QPushButton(plugin.MSG_ADD_FOUND) self.add_found_btn.clicked.connect(partial(self.add_found_coins, w)) hbox.addWidget(self.add_found_btn) hbox.addWidget(CloseButton(self)) g.addLayout(hbox, 11, 0, 1, -1) self.plugin.progress_sig.s.connect(self.on_progress_qt) self.plugin.completed_sig.s.connect(self.on_completed_qt) self.plugin.error_sig.s.connect(self.on_error_qt) self.cleaned_up = False ws = self.plugin.wallet_scans.get(w) self.scan_progress_pb.setValue(ws.progress) if ws.running: self.scan_cnt_sb.setEnabled(False) self.do_scan_btn.setEnabled(False) self.reset_scans_btn.setEnabled(False) self.set_add_found_bnt_state()